home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OWLSRC.PAK / WINDOW.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  87.1 KB  |  3,390 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1991, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.63  $
  6. //
  7. // Implementation of TWindow.  This defines the basic behavior of all Windows.
  8. //----------------------------------------------------------------------------
  9. #include <owl/pch.h>
  10. #if !defined(OWL_WINDOW_H)
  11. # include <owl/window.h>
  12. #endif
  13. #if !defined(OWL_APPLICAT_H)
  14. # include <owl/applicat.h>
  15. #endif
  16. #if !defined(OWL_APPDICT_H)
  17. # include <owl/appdict.h>
  18. #endif
  19. #if !defined(OWL_SCROLLER_H)
  20. # include <owl/scroller.h>
  21. #endif
  22. #if !defined(OWL_GDIOBJEC_H)
  23. # include <owl/gdiobjec.h>
  24. #endif
  25. #if !defined(OWL_MENU_H)
  26. # include <owl/menu.h>
  27. #endif
  28. #if !defined(OWL_FRAMEWIN_H)
  29. # include <owl/framewin.h>
  30. #endif
  31. #if !defined(OWL_COMMCTRL_H)
  32. # include <owl/commctrl.h>
  33. #endif
  34. #include <stdlib.h>
  35. #include <stdio.h>
  36.  
  37. OWL_DIAGINFO;
  38. DIAG_DECLARE_GROUP(OwlMsg);  // diagnostic group for message tracing
  39. DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlWin, 1, 0);  // diag. group for windows
  40. DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlCmd, 1, 0);  // diag. group for commands
  41.  
  42. //
  43. // Define to use rtti to create unique window ids for the message cache
  44. //
  45. #if defined(__BORLANDC__) && !defined(BI_NO_RTTI)
  46. # define OWL_RTTI_MSGCACHE
  47. # define TYPE_UNIQUE_UINT32(t)    reinterpret_cast<uint32>(typeid(t).tpp)
  48. #endif
  49.  
  50. //
  51. // Externs defined in owl.cpp
  52. //
  53. extern WNDPROC           CreateInstanceThunk(TWindow*, TThunkProc);
  54. extern void              FreeInstanceThunk(WNDPROC);
  55. extern void     _OWLFUNC SetCreationWindow(TWindow*);
  56. extern TWindow* _OWLFUNC GetCreationWindow();
  57. extern uint     _OWLDATA GetWindowPtrMsgId;
  58.  
  59.  
  60. DEFINE_RESPONSE_TABLE(TWindow)
  61.   EV_WM_SETCURSOR,
  62.   EV_WM_SIZE,
  63.   EV_WM_MOVE,
  64.   EV_WM_COMPAREITEM,
  65.   EV_WM_DELETEITEM,
  66.   EV_WM_DRAWITEM,
  67.   EV_WM_MEASUREITEM,
  68.   EV_WM_VSCROLL,
  69.   EV_WM_HSCROLL,
  70.   EV_WM_CHILDINVALID,
  71.   EV_WM_ERASEBKGND,
  72.   EV_WM_CTLCOLOR,
  73.   EV_WM_PAINT,
  74.   EV_WM_LBUTTONDOWN,
  75.   EV_WM_KILLFOCUS,
  76. #if defined(BI_PLAT_WIN32)
  77.   EV_MESSAGE(WM_CTLCOLORMSGBOX, EvWin32CtlColor),
  78.   EV_MESSAGE(WM_CTLCOLOREDIT, EvWin32CtlColor),
  79.   EV_MESSAGE(WM_CTLCOLORLISTBOX, EvWin32CtlColor),
  80.   EV_MESSAGE(WM_CTLCOLORBTN, EvWin32CtlColor),
  81.   EV_MESSAGE(WM_CTLCOLORDLG, EvWin32CtlColor),
  82.   EV_MESSAGE(WM_CTLCOLORSCROLLBAR, EvWin32CtlColor),
  83.   EV_MESSAGE(WM_CTLCOLORSTATIC, EvWin32CtlColor),
  84. #endif
  85.   EV_WM_CREATE,
  86.   EV_WM_CLOSE,
  87.   EV_WM_DESTROY,
  88.   EV_WM_NCDESTROY,
  89.   EV_WM_QUERYENDSESSION,
  90.   EV_WM_ENDSESSION,
  91.   EV_WM_SYSCOLORCHANGE,
  92.   EV_WM_INITMENUPOPUP,
  93.   EV_WM_CONTEXTMENU,
  94.   EV_WM_ENTERIDLE,
  95. END_RESPONSE_TABLE;
  96.  
  97.  
  98. #if defined(BI_NO_RTTI)
  99.   IMPLEMENT_CASTABLE1(TCommandEnabler, TStreamableBase);
  100. #endif
  101.  
  102. //
  103. //
  104. //
  105. TCommandEnabler::TCommandEnabler(uint id, HWND hReceiver)
  106. :
  107.   Id(id),
  108.   HWndReceiver(hReceiver)
  109. {
  110.   Flags = 0;
  111. }
  112.  
  113. //
  114. //
  115. //
  116. void
  117. TCommandEnabler::Enable(bool)
  118. {
  119.   Flags |= WasHandled;
  120. }
  121.  
  122. //
  123. // Constructor for a TWindow.  if a parent window is passed, adds the TWindow
  124. // to its parent's list of children
  125. //
  126. TWindow::TWindow(TWindow* parent, const char far* title, TModule* module)
  127. {
  128.   Thunk = 0;  // Zero out to remember that we still need to initialize
  129.   Init(parent, title, module);
  130. }
  131.  
  132. //
  133. // Constructor for a TWindow which is being used as an alias for a
  134. // non-OWL window.  This ctor is generally not used by derived classes
  135. //
  136. TWindow::TWindow(HWND handle, TModule* module)
  137. {
  138.   PRECONDITION(handle);
  139.  
  140.   Thunk = 0;  // Zero out to remember that we still need to initialize
  141.   Init(handle, module);
  142. }
  143.  
  144. //
  145. // Protected constructor for use by immediate virtually derived classes.
  146. // Immediate derivitives must call an Init() before constructions are done.
  147. //
  148. TWindow::TWindow()
  149. {
  150.   Thunk = 0;  // Zero out to remember that we still need to initialize
  151. }
  152.  
  153. //
  154. // Normal initialization of a default constructed TWindow. Is ignored if
  155. // called more than once.
  156. //
  157. void
  158. TWindow::Init(TWindow* parent, const char far* title, TModule* module)
  159. {
  160.   if (!Thunk) {
  161.     Title = strnewdup(title);
  162.     Init(parent, module);
  163.     DefaultProc = 0;
  164.     Handle = 0;
  165.     EnableAutoCreate();
  166.  
  167.     // Initialize creation attributes
  168.     //
  169.     Attr.Style = WS_CHILD | WS_VISIBLE;
  170.     Attr.X = Attr.Y = Attr.W = Attr.H = 0;
  171.     Attr.ExStyle = 0;
  172.     Attr.Id = 0;
  173.   }
  174. }
  175.  
  176. //
  177. // Wrapper initialization of a default constructed TWindow. Is ignored if
  178. // called more than once.
  179. //
  180. void
  181. TWindow::Init(HWND handle, TModule* module)
  182. {
  183.   PRECONDITION(handle);
  184.  
  185.   if (!Thunk) {
  186.     // Perform preliminary initialization
  187.     //
  188.     SetHandle(handle);
  189.     Title = 0;
  190.  
  191.     // If we've been given a module, then setup that and the app now if
  192.     // possible so that GetWindowPtr below has some context. Otherwise at least
  193.     // set it to 0.
  194.     //
  195.     Application = TYPESAFE_DOWNCAST(module,TApplication);
  196.  
  197.     // If the receiver's parent is an OWL window then pass the window to the
  198.     // private Init() so the receiver can be added to the parent's list of
  199.     // children
  200.     //
  201.     HWND   hParent = GetParentH();
  202.     TWindow*  parent = hParent ? GetWindowPtr(hParent) : 0;
  203.     Init(parent, module);
  204.  
  205.     // Thunk the window
  206.     //
  207.     SubclassWindowFunction();
  208.  
  209.     // Copy over the title, styles, the coordinates & the id
  210.     //
  211.     GetWindowTextTitle();
  212.     GetHWndState();
  213.  
  214.     // Keep track that this is an alias object & that it is already created
  215.     //
  216.     SetFlag(wfAlias | wfFullyCreated);
  217.  
  218.     // Unique id may have been set inadvertantly to TWindow by the above
  219.     // GetWindowTextTitle, et. al. Reset it just in case
  220.     //
  221.     SetUniqueId();
  222.   }
  223. }
  224.  
  225. //
  226. // Private initializer function that does the bulk of the work for the
  227. // protected Init()s
  228. //
  229. void
  230. TWindow::Init(TWindow* parent, TModule* module)
  231. {
  232.   ZOrder = 0;
  233.   ChildList = 0;
  234.   Flags = wfDeleteOnClose;
  235.   TransferBuffer = 0;
  236.   Parent = parent;
  237.   Attr.Param = 0;
  238.   Attr.Menu = 0;
  239.   Attr.AccelTable = 0;
  240.   HAccel = 0;
  241.   Thunk = ::CreateInstanceThunk(this, StdWndProc);
  242.   Scroller = 0;
  243.   ContextPopupMenu = 0;
  244.  
  245.   CursorModule = 0;
  246.   CursorResId = 0;
  247.   HCursor = 0;
  248.   BkgndColor = TColor::None;
  249.  
  250.   if (Parent)
  251.     Parent->AddChild(this);
  252.   else
  253.     SiblingList = 0;
  254.  
  255.   // Use passed module if one, else get parent's. If no parent, use app
  256.   //
  257.   if (Parent) {
  258.     Application = Parent->GetApplication();
  259.     Module = module ? module : Parent->GetModule();
  260.   }
  261.   else {
  262.     Module = module ? module : 0;
  263.     Application = TYPESAFE_DOWNCAST(Module,TApplication);
  264.     if (!Application) {
  265.       Application = ::GetApplicationObject();
  266.       if (!Module)
  267.         Module = Application;
  268.     }
  269.     CHECK(Application);
  270.   }
  271.   SetUniqueId();
  272.  
  273.   TRACEX(OwlWin, 1, "TWindow constructed @" << (void*)this << *this);
  274. }
  275.  
  276. //
  277. // Installs the thunk as the window function and saves the old window function
  278. // in the DefaultProc member
  279. //
  280. void
  281. TWindow::SubclassWindowFunction()
  282. {
  283.   PRECONDITION(GetHandle());
  284.  
  285. #if defined(BI_PLAT_WIN32)
  286.   uint32 processId;
  287.   ::GetWindowThreadProcessId(GetHandle(), &processId);
  288.   if (processId == ::GetCurrentProcessId())
  289. #else
  290.   if (::GetWindowTask(GetHandle()) == ::GetCurrentTask())
  291. #endif
  292.   {
  293.     DefaultProc = (WNDPROC)SetWindowLong(GWL_WNDPROC, uint32(GetThunk()));
  294.     CHECK(DefaultProc != GetThunk());  // can only be called once!
  295.   }
  296. }
  297.  
  298. //
  299. // Destructor for a TWindow: disposes of each window in its ChildList
  300. // and removes itself from a non-0 parent's list of children
  301. //
  302. // Destroys a still-associated Handle and frees the instance thunk used for
  303. // linking the TWindow to the Handle
  304. //
  305. // Disposes of its Scroller if the TScroller object was constructed
  306. //
  307. static void shutDown(TWindow* win, void*) {
  308.   win->Destroy();
  309.   delete win;
  310. }
  311.  
  312. //
  313. //
  314. //
  315. TWindow::~TWindow()
  316. {
  317.   // Flush the cache so that messages dont get dispatched to a
  318.   // already-destructed derived class
  319.   //
  320.   void CacheFlush(uint32 id);
  321.   CacheFlush(UniqueId);
  322.  
  323.   // ShutDown children first, so the Owl objects get a chance to clean up
  324.   //
  325.   ForEach(shutDown);
  326.  
  327.   // If the Handle is still around, then destroy it or unlink from it as
  328.   // appropriate.
  329.   //
  330.   if (GetHandle()) {
  331.     // For aliases:
  332.     //  - we are destructing the C++ object but not destroying the MS window
  333.     //  - restore the original window function
  334.     //
  335.     if (IsFlagSet(wfAlias)) {
  336.       // May want to check WNDPROC against Thunk to see if its still us
  337.       // and not restore if it's not us...
  338.       //
  339.       WARNX(OwlWin, GetWindowLong(GWL_WNDPROC) != (int32)GetThunk(), 0,
  340.             "Restoring old WndProc after foreign subclass of:" << *this);
  341.       SetWindowLong(GWL_WNDPROC, uint32(DefaultProc));
  342.     }
  343.     // For non-aliases:
  344.     //  - destroy the windows element
  345.     // this is not a normal condition and is a safety net only
  346.     //
  347.     else {
  348.       WARNX(OwlWin, GetHandle(), 0, "Destroying from TWindow::~TWindow: " << *this);
  349.       Destroy();
  350.     }
  351.   }
  352.  
  353.   // Remove from parent's ChildList
  354.   //
  355.   if (Parent)
  356.     Parent->RemoveChild(this);
  357.  
  358. #if 0
  359.   // Clear TApplication's member to avoid dangling pointer
  360.   //
  361.   //
  362.   if (IsFlagSet(wfMainWindow))
  363.     GetApplication()->MainWindow = 0;
  364. #endif
  365.  
  366.   // Remove pointer from application's CondemnList
  367.   //
  368.   if (Application)
  369.     Application->Uncondemn(this);
  370.  
  371.   // Delete menu id string, scroller, title, cursor & thunk
  372.   //
  373.   if (Attr.Menu.IsString())
  374.     delete[] (char far*)Attr.Menu;  // Assumes strnewdup was used
  375.  
  376.   // Get rid of our scroller, if any.
  377.   //
  378.   SetScroller(0);
  379.  
  380.   // Clean up title member
  381.   //
  382.   if (HiUint16(uint32(Title)))
  383.     delete[] Title;
  384.   Title = 0;
  385.  
  386.   // Cleanup cursor
  387.   //
  388.   if (HCursor && CursorModule)
  389.     SetCursor(0, 0);
  390.  
  391.   // Clean up context menu object
  392.   //
  393.   delete ContextPopupMenu;
  394.  
  395.   // Clean up thunk
  396.   //
  397.   ::FreeInstanceThunk(Thunk);
  398.   TRACEX(OwlWin, 1, "TWindow destructed @" << (void*)this << *this);
  399. }
  400.  
  401. #if defined(BI_MULTI_THREAD_RTL)
  402. //
  403. // Overrides TEventHandler::Dispatch() to handle multi-thread synchronization
  404. //
  405. TResult TWindow::Dispatch(TEventInfo& info, TParam1 p1, TParam2 p2)
  406. {
  407.   TApplication::TQueueLock lock(*GetApplication());
  408.   return TEventHandler::Dispatch(info, p1, p2);
  409. }
  410.  
  411. #endif
  412.  
  413. //
  414. // Called from TApplication::ProcessAppMsg() to give the window an
  415. // opportunity to perform preprocessing of the Windows message
  416. //
  417. // If you return true, further processing of the message is halted
  418. //
  419. // If you override this method in a derived class, make sure to call this
  420. // routine because it handles translation of accelerators...
  421. //
  422. bool
  423. TWindow::PreProcessMsg(MSG& msg)
  424. {
  425.   PRECONDITION(GetHandle());
  426.  
  427.   return HAccel ? ::TranslateAccelerator(GetHandle(), HAccel, &msg) : false;
  428. }
  429.  
  430. //
  431. // Propagate idle action to all children if count==0, and to any children that
  432. // previously said they wanted more time.
  433. //
  434. bool
  435. TWindow::IdleAction(long idleCount)
  436. {
  437.   bool wantMore = false;
  438.   TWindow* win = GetFirstChild();
  439.   if (win) {
  440.     do {
  441.       if (idleCount == 0 || win->IsFlagSet(wfPropagateIdle)) {
  442.         if (win->IdleAction(idleCount)) {
  443.           win->SetFlag(wfPropagateIdle);
  444.           wantMore = true;
  445.         }
  446.         else {
  447.           win->ClearFlag(wfPropagateIdle);
  448.         }
  449.       }
  450.       win = win->Next();
  451.     } while (win && win != GetFirstChild());
  452.   }
  453.   return wantMore;
  454. }
  455.  
  456. //
  457. // Respond to WM_SYSCOLORCHANGE by broadcasting it to all children
  458. //
  459. void
  460. TWindow::EvSysColorChange()
  461. {
  462.   ChildBroadcastMessage(WM_SYSCOLORCHANGE);
  463.   DefaultProcessing();
  464. }
  465.  
  466. //
  467. // Removes the passed pointer to a child window from the linked list of
  468. // sibling windows which the TWindow's ChildList points to
  469. //
  470. void
  471. TWindow::RemoveChild(TWindow* child)
  472. {
  473.   if (child && ChildList) {
  474.     TWindow*  lastChild = ChildList;
  475.     TWindow*  nextChild = lastChild;
  476.  
  477.     while (nextChild->SiblingList != lastChild &&
  478.            nextChild->SiblingList != child) {
  479.       nextChild = nextChild->SiblingList;
  480.     }
  481.  
  482.     if (nextChild->SiblingList == child) {
  483.       if (nextChild->SiblingList == nextChild)
  484.         ChildList = 0;
  485.  
  486.       else {
  487.         if (nextChild->SiblingList == ChildList)
  488.           ChildList = nextChild;
  489.  
  490.         nextChild->SiblingList = nextChild->SiblingList->SiblingList;
  491.       }
  492.     }
  493.   }
  494. }
  495.  
  496. //
  497. // Reparents this window to a new owl parent window. Also sets the windows
  498. // parent (owner really)
  499. //
  500. void
  501. TWindow::SetParent(TWindow* newParent)
  502. {
  503.   if (Parent != newParent) {
  504.     if (Parent)
  505.       Parent->RemoveChild(this);
  506.  
  507.     SiblingList = 0;
  508.  
  509.     Parent = newParent;
  510.  
  511.     if (Parent)
  512.       Parent->AddChild(this);
  513.   }
  514.   // Tell Windows about the change too, if appropriate
  515.   //
  516.   if (GetHandle() && Parent && GetParentH() != Parent->GetHandle()) {
  517.     if (newParent) {
  518.       if (newParent->GetHandle())
  519.         ::SetParent(GetHandle(), newParent->GetHandle());
  520.     }
  521.     else
  522.       ::SetParent(GetHandle(), 0);
  523.   }
  524. }
  525.  
  526. //
  527. // Default behavior for updating document title is to pass it to parent frame
  528. //
  529. bool
  530. TWindow::SetDocTitle(const char far* docname, int index)
  531. {
  532.   return Parent ? Parent->SetDocTitle(docname, index) : false;
  533. }
  534.  
  535. //
  536. // Set the scroller object for this window. This window assumes ownership of
  537. // the scroller object, & will delete it when done & on subsequent sets.
  538. //
  539. void
  540. TWindow::SetScroller(TScroller* scroller)
  541. {
  542.   if (Scroller) {
  543.     // Delete scroller if there is one, by casting up to base and relying on
  544.     // virtual dtor to avoid forcing in TScroller object code.
  545.     //
  546.     delete (TStreamableBase*)Scroller;
  547.   }
  548.   Scroller = scroller;
  549. }
  550.  
  551. //
  552. // Wildcard check used for child id notifications
  553. //
  554. static bool wildcardCheck(TGenericTableEntry __RTFAR& entry,
  555.                           TEventHandler::TEventInfo& info) {
  556.   return entry.Id == info.Id && (entry.Msg == UINT_MAX || entry.Msg == info.Msg);
  557. }
  558.  
  559. //
  560. // Handles default processing of events, which includes continued processing
  561. // of menu/accelerators commands and enablers, as well as notifications
  562. //
  563. TResult
  564. TWindow::DefaultProcessing()
  565. {
  566.   TCurrentEvent& currentEvent = GetCurrentEvent();
  567.  
  568.   if (currentEvent.Message == WM_COMMAND_ENABLE) {
  569.     if (currentEvent.Win != this) {
  570.       TWindow*         receiver = Parent ? Parent : currentEvent.Win;
  571.       TCommandEnabler& commandEnabler = *(TCommandEnabler*)currentEvent.Param2;
  572.       TEventInfo       eventInfo(WM_COMMAND_ENABLE, commandEnabler.Id);
  573.  
  574.       if (receiver->Find(eventInfo))
  575.         return receiver->Dispatch(eventInfo, 0, currentEvent.Param2);
  576.     }
  577.  
  578.     return 0;
  579.   }
  580.  
  581.   // Handle normal message default processing by routing directly to the
  582.   // virtual DefWindowProc() for the window.
  583.   //
  584.   if (currentEvent.Message != WM_COMMAND && currentEvent.Message != WM_NOTIFY)
  585.     return DefWindowProc(currentEvent.Message,
  586.                          currentEvent.Param1,
  587.                          currentEvent.Param2);
  588.  
  589.   // currentEvent.Message == WM_COMMAND or WM_NOTIFY
  590.   //
  591.   uint    notifyCode;
  592.   uint    id;
  593.   HWND hWndCtl;
  594.  
  595.   // Get notify code, control id and control handle from packed params.
  596.   // Unpacking based on message & platform.
  597.   //
  598.   if (currentEvent.Message == WM_COMMAND) {
  599. #if defined(BI_PLAT_WIN16)
  600.     notifyCode = HiUint16(currentEvent.Param2);
  601. #else
  602.     notifyCode = HiUint16(currentEvent.Param1);
  603. #endif
  604.     id = LoUint16(currentEvent.Param1);
  605.     hWndCtl = HWND((uint)currentEvent.Param2);
  606.   }
  607.   else {
  608.     notifyCode = ((TNotify*)currentEvent.Param2)->code;
  609.     id = currentEvent.Param1;
  610.     hWndCtl = ((TNotify*)currentEvent.Param2)->hwndFrom;
  611.   }
  612.  
  613.   // If all special routing is done, then process the command/notify for this
  614.   // window
  615.   //
  616.   if (currentEvent.Win == this) {
  617.     // Menu command originally destined for the receiver, defer to the app.
  618.     //
  619.     if (hWndCtl == 0) {
  620.       TEventInfo     eventInfo(0, id);
  621.       TApplication*  app = GetApplication();
  622.  
  623.       if (app->Find(eventInfo)) {
  624.         app->Dispatch(eventInfo, eventInfo.Id);
  625.         return 0;
  626.       }
  627.       WARNX(OwlMsg, notifyCode<=1, 0, "Unprocessed WM_COMMAND(id=" << id << ")");
  628.     }
  629.     // Originally destined for the receiver and the receiver has called us so
  630.     // default processing can occur.
  631.     // Unpack the original parameters and call DefWindowProc()
  632.     //
  633.     return DefWindowProc(currentEvent.Message, currentEvent.Param1, currentEvent.Param2);
  634.   }
  635.  
  636.   // Perform special routing for commands and notifications
  637.   //
  638.   else {
  639.     TWindow*        receiver;
  640.     TEqualOperator  equal = 0;
  641.  
  642.     if (hWndCtl == 0) {
  643.       // Menu/accelerator/push button
  644.       // Either give the message to the receiver's parent or the original
  645.       // receiver of the message
  646.       //
  647.       receiver = Parent ? Parent : currentEvent.Win;
  648.  
  649.       // "notifyCode" is either 0 or 1 depending on whether this is from an
  650.       // accelerator; however, we want to explicitly look for a 0...
  651.       //
  652.       notifyCode = 0;
  653.     }
  654.     else {
  655.       // Child id notification (either WM_COMMAND or WM_NOTIFY) sent to the
  656.       // child and the child has called us.
  657.       // Offer the parent an opportunity to handle the notification
  658.       //   NOTE: use equal function that will do a wildcard search
  659.       //
  660.       equal = wildcardCheck;
  661.       receiver = currentEvent.Win;
  662.  
  663.       // The child window identifier shouldn't be 0, but if it is then it will
  664.       // look like we are searching for a WM_ message with value "notifyCode",
  665.       // in that case just give up and call DefWindowProc() for the window.
  666.       //
  667.       if (receiver->IsFlagSet(wfAlias) || id == 0)
  668.         return receiver->DefWindowProc(currentEvent.Message,
  669.                                        currentEvent.Param1,
  670.                                        currentEvent.Param2);
  671.     }
  672.  
  673.     // Now dispatch the command or notification to the receiver window
  674.     //
  675.     TEventInfo  eventInfo(notifyCode, id);
  676.  
  677.     // NOTE: The ResponseTableEntry of handlers which expect an id (e.g.
  678.     //       EV_COMMAND_AND_ID) have a zero in their first field. The
  679.     //       ResponseTableEntry of handlers which expect a notification code
  680.     //       (e.g. EV_CHILD_NOTIFY_AND_CODE and EV_NOTIFY_ALL_CODES) contain
  681.     //       either the notifyCode or UINT_MAX in that field. Hence, we can
  682.     //       dispatch the expected information based on the contents of that
  683.     //       field.
  684.     //
  685.     //       However, this logic will fail to disambiguate cases where a
  686.     //       notification code is 0. The only standard control with such a
  687.     //       notification is BUTTON /w BN_CLICKED. So for button handlers
  688.     //       expecting the id, you can use EV_COMMAND_AND_ID. For handlers
  689.     //       expecting the notification code, you can use EV_NOTIFY_ALL_CODES,
  690.     //       (*NOT* EV_CHILD_NOTIFY_AND_CODE(Id, BN_CLICKED, xxxx,...))
  691.     //
  692.     if (receiver->Find(eventInfo, equal)) {
  693.       TParam1 param1 = eventInfo.Entry->NotifyCode ? notifyCode : id;
  694.       return receiver->Dispatch(eventInfo, param1, currentEvent.Param2);
  695.     }
  696.     else
  697.       return receiver->DefaultProcessing();
  698.   }
  699. }
  700.  
  701. //
  702. // Called by WindowProc() to handle WM_COMMANDs
  703. //
  704. // id         - specifies the identifier of the menu item or control
  705. //
  706. // hWndCtl    - specifies the control sending the message if the message
  707. //              is from a control; otherwise it is 0
  708. //
  709. // notifyCode - specifies the notification message if the message is from
  710. //              a control. if the message is from an accelerator, it is 1.
  711. //              if the message is from a menu, it is 0
  712. //
  713. TResult
  714. TWindow::EvCommand(uint id, HWND hWndCtl, uint notifyCode)
  715. {
  716.   TRACEX(OwlCmd, 1, "TWindow::EvCommand - id(" << id << "), ctl(" <<\
  717.                      hex << uint(hWndCtl) << "), code(" << notifyCode  << ")");
  718.  
  719.   TWindow*        receiver = this;
  720.   TEqualOperator  equal = 0;
  721.  
  722.   // Menu/accelerator
  723.   //
  724.   if (hWndCtl == 0) {
  725.     // "notifyCode" is either 0 or 1 depending on whether this is from an
  726.     // accelerator; however, we want to explicitly look for a 0 in the tables
  727.     //
  728.     notifyCode = 0;
  729.   }
  730.  
  731.   // Child id notification
  732.   //
  733.   else {
  734.     TWindow*  child = GetWindowPtr(hWndCtl);
  735.  
  736.     if (child) {
  737.       // Give the child first crack at the event
  738.       //
  739.       receiver = child;
  740.       id = UINT_MAX;  // special designator for child Id notifications that are
  741.                       // handled at the child
  742.     }
  743.     else {
  744.       // Offer the parent an opportunity to handle the notification
  745.       //
  746.       // NOTE: use equal function that will do a wildcard search
  747.       //
  748.       equal = wildcardCheck;
  749.  
  750.       // The child window identifier shouldn't be 0, but if it is then it will
  751.       // look like we are searching for a WM_ message with value "notifyCode"
  752.       //
  753.       if (id == 0)
  754.         return DefaultProcessing();
  755.     }
  756.   }
  757.  
  758.   TEventInfo  eventInfo(notifyCode, id);
  759.  
  760.   // NOTE: The ResponseTableEntry of handlers which expect an id
  761.   //       (e.g. EV_COMMAND_AND_ID) have a zero in their first field.
  762.   //       The ResponseTableEntry of handlers which expect a notification
  763.   //       code (e.g. EV_CHILD_NOTIFY_AND_CODE and EV_NOTIFY_ALL_CODES)
  764.   //       contain either the notifyCode or UINT_MAX in that field.
  765.   //       Hence, we can dispatch the expected information based on the
  766.   //       contents of that field.
  767.   //
  768.   //       However, this logic will fail to disambiguate cases where
  769.   //       a notification code is 0. The only standard control with
  770.   //       such a notification is BUTTON /w BN_CLICKED. So for button
  771.   //       handlers expecting the id, you can use EV_COMMAND_AND_ID.
  772.   //       For handlers expecting the notification code, you can use
  773.   //       EV_NOTIFY_ALL_CODES.
  774.   //
  775.   //       Do *NOT* use "EV_CHILD_NOTIFY_AND_CODE(Id, BN_CLICKED, xxxx,...)"
  776.   //
  777.   if (receiver->Find(eventInfo, equal))
  778.     return receiver->Dispatch(eventInfo,
  779.                               eventInfo.Entry->NotifyCode ? notifyCode : id);
  780.   else
  781.     return receiver->DefaultProcessing();
  782. }
  783.  
  784. //
  785. // Handle WM_NOTIFY & subdispatch messages from child controls
  786. //
  787. TResult
  788. TWindow::EvNotify(uint ctlId, TNotify& notifyInfo)
  789. {
  790.   TWindow*        receiver = this;
  791.   TEqualOperator  equal = 0;
  792.   TWindow*        child = GetWindowPtr(notifyInfo.hwndFrom);
  793.  
  794.   if (child) {
  795.     // Give the Owl child first crack at the event
  796.     //
  797.     receiver = child;
  798.     ctlId = UINT_MAX;// special designator for child Id notifications that are
  799.                      // handled at the child 
  800.   }
  801.   else {
  802.     // Offer the parent an opportunity to handle the notification
  803.     //   NOTE: use equal function that will do a wildcard search
  804.     //
  805.     equal = wildcardCheck;
  806.  
  807.     // The child window identifier shouldn't be 0, but if it is then it will
  808.     // look like we are searching for a WM_ message with value "notifyCode"
  809.     //
  810.     if (ctlId == 0)
  811.       return DefaultProcessing();
  812.   }
  813.  
  814.   TEventInfo  eventInfo(notifyInfo.code, ctlId);
  815.  
  816.   // Pass the "notifyCode" along in case the user wants it...
  817.   //
  818.   if (receiver->Find(eventInfo, equal))
  819.     return receiver->Dispatch(eventInfo, notifyInfo.code, TParam2(¬ifyInfo));
  820.   else
  821.     return receiver->DefaultProcessing();
  822. }
  823.  
  824. //
  825. // Handle an ObjectWindow's defined WM_COMMANDENABLE message by
  826. // sub-dispatching it based on the command id
  827. //
  828. void
  829. TWindow::EvCommandEnable(TCommandEnabler& commandEnabler)
  830. {
  831.   DispatchMsg(WM_COMMAND_ENABLE, commandEnabler.Id, 0, TParam2(&commandEnabler));
  832. }
  833.  
  834. //
  835. // Don't process for windows out of our window tree (esp. other apps)
  836. //
  837. void
  838. TWindow::RouteCommandEnable(HWND hInitCmdTarget, TCommandEnabler& commandEnabler)
  839. {
  840.   // Extra processing for commands & commandEnablers: send the command down the
  841.   // command chain if we are the original receiver
  842.   //
  843.   if (commandEnabler.IsReceiver(*this)) {
  844.     HWND  hCmdTarget = hInitCmdTarget;
  845.     while (hCmdTarget && hCmdTarget != *this) {
  846.       TWindow*  cmdTarget = GetWindowPtr(hCmdTarget);
  847.  
  848.       if (cmdTarget) {
  849.         cmdTarget->EvCommandEnable(commandEnabler);
  850.  
  851.         if (commandEnabler.GetHandled())
  852.           return;
  853.       }
  854.       hCmdTarget = ::GetParent(hCmdTarget);
  855.     }
  856.   }
  857.  
  858.   // Always call base handler
  859.   //
  860.   TWindow::EvCommandEnable(commandEnabler);
  861.  
  862.   // No one explicitly enabled/disabled the command via the enabler, so run up
  863.   // the command chain checking for any one who is going to handle the command
  864.   // itself; if not then disable it...
  865.   // Don't do this for command senders that don't actually generate commands,
  866.   // like popup menu items.
  867.   //
  868.   if (commandEnabler.IsReceiver(*this) && !commandEnabler.GetHandled()
  869.       && commandEnabler.SendsCommand()) {
  870.     bool        enable = false;
  871.     TEventInfo  eventInfo(0, commandEnabler.Id);
  872.  
  873.     HWND  hCmdTarget = hInitCmdTarget;
  874.     while (true) {
  875.       TWindow*  cmdTarget = GetWindowPtr(hCmdTarget);
  876.  
  877.       if (cmdTarget && cmdTarget->Find(eventInfo)) {
  878.         enable = true;  // command will be handled, leave sender alone
  879.         break;
  880.       }
  881.       if (!hCmdTarget || hCmdTarget == *this)
  882.         break;
  883.  
  884.       hCmdTarget = ::GetParent(hCmdTarget);
  885.     }
  886.  
  887.     if (!enable) {
  888.       // Check if the app wants to handle it
  889.       //
  890.       TEventInfo    enableInfo(WM_COMMAND_ENABLE, commandEnabler.Id);
  891.       TApplication* app = GetApplication();
  892.       if (app->Find(enableInfo)) {
  893.         app->Dispatch(enableInfo, 0, TParam2(&commandEnabler));
  894.         if (commandEnabler.GetHandled())
  895.           return;
  896.       }
  897.       enable = app->Find(eventInfo);
  898.     }
  899.  
  900.     commandEnabler.Enable(enable);
  901.   }
  902. }
  903.  
  904. //
  905. // Virtual function provides final default processing for an incoming message
  906. // Calls original window proc that was subclassed, using ::CallWindowProc to
  907. // make sure that registers get setup correctly.
  908. //
  909. TResult
  910. TWindow::DefWindowProc(uint message, TParam1 param1, TParam2 param2)
  911. {
  912.   PRECONDITION(DefaultProc);
  913.  
  914.   TResult result = ::CallWindowProc(DefaultProc, GetHandle(), message, param1, param2);
  915.   GetApplication()->ResumeThrow();
  916.   return result;
  917. }
  918.  
  919. #if defined(BI_NAMESPACE)
  920. namespace OWL {
  921. #endif 
  922.  
  923. //
  924. // Message cache
  925. //
  926. static const int     msgCacheSize = 31;
  927. struct TCacheEntry {
  928.   uint32                       UniqueId;
  929.   TGenericTableEntry  __RTFAR* Entry;
  930.   uint                         Msg;
  931.   int                          Delta;  // adjustment to "this" pointer
  932.  
  933.   void Set(uint32 uniqueId, uint msg, TGenericTableEntry __RTFAR* entry, int delta = 0) {
  934.     UniqueId = uniqueId;
  935.     Entry = entry;
  936.     Msg = msg;
  937.     Delta = delta;
  938.   }
  939.   bool  Hit(uint msg, uint32 uniqueId) {return msg == Msg && uniqueId == UniqueId;}
  940.  
  941.   static uint  Key(uint32 id, uint msg) {return (uint(id) ^ msg) % msgCacheSize;}
  942. };
  943.  
  944. uint32 TWindow::LastUniqueId = 0;
  945.  
  946. static TCacheEntry  msgCache[msgCacheSize];
  947. static bool         cacheEnabled = true;
  948.  
  949. void CacheFlush(uint32 id) {
  950.   for (int i = 0; i < msgCacheSize; i++)
  951.     if (msgCache[i].UniqueId == id)
  952.       msgCache[i].Msg = 0;
  953. }
  954.  
  955. #if defined(BI_NAMESPACE)
  956. } // namespace OWL
  957. #endif 
  958.  
  959. //
  960. // If rtti is available, then use it get an id for this window that is unique
  961. // on a per-class basis.
  962. //
  963. // Without rtti, use a per-instance unique id. Less efficient, but safe.
  964. //
  965. void
  966. TWindow::SetUniqueId()
  967. {
  968. #if defined(OWL_RTTI_MSGCACHE)
  969.   UniqueId = 0;
  970. #else
  971.   if (++LastUniqueId == 0) {
  972.     //
  973.     // numbers wrapped around. disable the cache to be safe...
  974.     //
  975.     LastUniqueId = 1;
  976.     cacheEnabled = false;
  977.   }
  978.   UniqueId = LastUniqueId;
  979. #endif
  980. }
  981.  
  982. //
  983. // First virtual function called to handling incoming messages to a TWindow
  984. //
  985. // Hand calls handler for WM_COMMAND, WM_COMMAND_ENABLE and WM_NOTIFY.
  986. // otherwise looks for a handler in the message response table
  987. //
  988. TResult
  989. TWindow::WindowProc(uint msg, TParam1 param1, TParam2 param2)
  990. {
  991.   PRECONDITION(GetHandle());  // Should never get here without a handle
  992.  
  993.   // Handle WM_COMMAND_ENABLE command enable msgs by directly calling the
  994.   // virtual EvCommandEnable
  995.   //
  996.   if (msg == WM_COMMAND_ENABLE) {
  997.     TRACEX(OwlMsg, 1, "WM_COMMAND_ENABLE" << "! => " << *this);
  998.     EvCommandEnable(*(TCommandEnabler*)param2);
  999.     return 0;
  1000.   }
  1001.   // Handle WM_COMMAND command msgs by directly calling the
  1002.   // virtual EvCommand
  1003.   //
  1004.   else if (msg == WM_COMMAND) {
  1005.     TRACEX(OwlMsg, 1, "WM_COMMAND, " << LoUint16(param1) << " ! => " << *this);
  1006. #if defined(BI_PLAT_WIN16)
  1007.     return EvCommand(LoUint16(param1), HWND(uint(param2)), HiUint16(param2));
  1008. #else
  1009.     return EvCommand(LoUint16(param1), HWND(uint(param2)), HiUint16(param1));
  1010. #endif
  1011.   }
  1012.   // Handle WM_NOTIFY msgs by directly calling the virtual EvNotify
  1013.   //
  1014.   else if (msg == WM_NOTIFY) {
  1015.  
  1016.     // We've received reports of some controls (out there) sending
  1017.     // WM_NOTIFY with a NULL LPARAM !!
  1018.     //
  1019.     static TNotify dumbNMHDR;
  1020.     TNotify* not = param2 ? (TNotify*)param2 : &dumbNMHDR;
  1021.  
  1022.     TRACEX(OwlMsg, 1, "WM_NOTIFY, " << not->idFrom   << ", "\
  1023.                                     << not->code     << ", "\
  1024.                                     << hex << uint(not->hwndFrom) << ", "\
  1025.                                     << " ! => " << *this);
  1026.     return EvNotify(param1, *not);
  1027.   }
  1028.  
  1029.   // Handle all other messages by looking up and dispatching using the
  1030.   // response tables
  1031.   //
  1032.   else {
  1033. #if defined(OWL_RTTI_MSGCACHE)
  1034.     if (!UniqueId)
  1035.       UniqueId = TYPE_UNIQUE_UINT32(*this);
  1036. #endif
  1037.     uint        key = TCacheEntry::Key(UniqueId, msg);
  1038.     TEventInfo  eventInfo(msg);
  1039.  
  1040.     // Check the cache. A cache hit may be an RT handler, or an RT miss.
  1041.     //
  1042.     if (cacheEnabled && msgCache[key].Hit(msg, UniqueId)) {
  1043.       eventInfo.Entry = msgCache[key].Entry;
  1044.       if (eventInfo.Entry) {
  1045.         TRACEX(OwlMsg, 1, MsgName(msg) << "* => " << *this);
  1046.         eventInfo.Object = (GENERIC*)(((char*)this) + msgCache[key].Delta);
  1047.         return Dispatch(eventInfo, param1, param2);
  1048.  
  1049.       } // else fall out & do default below
  1050.     }
  1051.     // Perform the lookup on this window.
  1052.     //
  1053.     else if (Find(eventInfo)) {
  1054.       TRACEX(OwlMsg, 1, MsgName(msg) << "  => " << *this);
  1055.       msgCache[key].Set(UniqueId, msg, eventInfo.Entry, int(eventInfo.Object) - int(this));
  1056.       return Dispatch(eventInfo, param1, param2);
  1057.     }
  1058.     else  // not found
  1059.       msgCache[key].Set(UniqueId, msg, 0);  // Cache no-handler entries too
  1060.  
  1061.     // Behavior for messages that have no handler. If this is the main window,
  1062.     // then give the app a chance to handle the message. If not the main
  1063.     // window, or if the app had no handler, just call DefWindowProc() to
  1064.     // pass the message back to whomever we subclassed
  1065.     //
  1066.     if (IsFlagSet(wfMainWindow)) {
  1067.       TEventInfo cmdEventInfo(msg, param1);
  1068.       if (GetApplication()->Find(cmdEventInfo))
  1069.         return GetApplication()->Dispatch(cmdEventInfo, param1, param2);
  1070.       if (GetApplication()->Find(eventInfo))
  1071.         return GetApplication()->Dispatch(eventInfo, param1, param2);
  1072.     }
  1073.     return DefWindowProc(msg, param1, param2);
  1074.   }
  1075. }
  1076.  
  1077. //
  1078. // Save current event and call this window's WindowProc. Handles exceptions,
  1079. // error checking, & GetWindowPtr messages.
  1080. //
  1081. TResult
  1082. TWindow::HandleMessage(uint msg, TParam1 param1, TParam2 param2)
  1083. {
  1084.   // Save event away in "CurrentEvent"
  1085.   //
  1086.   TCurrentEvent& currentEvent = GetCurrentEvent();
  1087.   TCurrentEvent  saveEvent = currentEvent;  // for nested calls
  1088.   currentEvent.Win = this;
  1089.   currentEvent.Message = msg;
  1090.   currentEvent.Param1 = param1;
  1091.   currentEvent.Param2 = param2;
  1092.  
  1093.   // Call window object's WindowProc virtual function
  1094.   //
  1095.   TResult  result;
  1096.   result = WindowProc(msg, param1, param2);
  1097.   currentEvent = saveEvent;  // restore previous event to current event
  1098.   return result;
  1099. }
  1100.  
  1101. //
  1102. // Window function called for normal, initialized, OWL windows via a
  1103. // per-window thunk. 'this' ptr is setup in register(s) by the thunk before
  1104. // StdWndProc is called.
  1105. //
  1106. #if defined(BI_PLAT_WIN16)
  1107. TResult CALLBACK OWL_EXPORT16
  1108. TWindow::StdWndProc(HWND, uint msg, TParam1 param1, TParam2 param2)
  1109. {
  1110.   return ((TWindow*)MK_FP(_ES,_BX))->ReceiveMessage(msg, param1, param2);
  1111. }
  1112. #else
  1113. /*OWL_EXPORT*/ TResult CALLBACK
  1114. TWindow::StdWndProc(HWND, uint msg, TParam1 param1, TParam2 param2)
  1115. {
  1116. #if defined(BI_COMP_BORLANDC)
  1117.   return ((TWindow*)_EAX)->ReceiveMessage(msg, param1, param2);
  1118. #else
  1119.   TWindow* w;
  1120.   _asm mov w, eax
  1121.   return w->ReceiveMessage(msg, param1, param2);
  1122. #endif
  1123. }
  1124. #endif
  1125.  
  1126. //
  1127. // First member function that receives messages from windows thru the
  1128. // thunk & then StdWndProc. Deals with exception suspension for non-NT
  1129. // environments.
  1130. //
  1131. TResult
  1132. TWindow::ReceiveMessage(uint msg, TParam1 param1, TParam2 param2)
  1133. {
  1134.   // If it's a "GetWindowPtr" message, then return pointer to this window
  1135.   //
  1136.   if (msg == ::GetWindowPtrMsgId && (!param2 || param2 == TParam2(Application)))
  1137.     return TResult(this);
  1138.  
  1139. #if defined(BI_PLAT_WIN32)
  1140.   if (TSystem::SupportsExceptions())
  1141.     return HandleMessage(msg, param1, param2);
  1142. #endif
  1143. #if defined(BI_PLAT_WIN16) || defined(WIN32S_SUPPORT)
  1144.   TRY {
  1145.     return HandleMessage(msg, param1, param2);
  1146.   }
  1147.   CATCH( (TXOwl& x) {
  1148.     GetApplication()->SuspendThrow(x);
  1149.   })
  1150.   CATCH( (xalloc& x) {
  1151.     GetApplication()->SuspendThrow(x);
  1152.   })
  1153.   CATCH( (xmsg& x) {
  1154.     GetApplication()->SuspendThrow(x);
  1155.   })
  1156. #if !defined(BI_NO_NEW_CASTS)
  1157.   CATCH( (Bad_cast& x) {
  1158.     GetApplication()->SuspendThrow(TApplication::xsBadCast);
  1159.   })
  1160.   CATCH( (Bad_typeid& x) {
  1161.     GetApplication()->SuspendThrow(TApplication::xsBadTypeid);
  1162.   })
  1163. #endif
  1164.   CATCH( (...) {
  1165.     GetApplication()->SuspendThrow(TApplication::xsUnknown);
  1166.   })
  1167.   ENDCATCH
  1168. #endif
  1169.  
  1170.   // When exceptions are disabled CATCH is defined as empty, so the only code
  1171.   // is the TRY block, making this return unreachable
  1172.   //
  1173. # pragma warn -rch
  1174.   return msg == WM_CREATE ? -1 : 0;  // default value returned when exception caught
  1175. # pragma warn .rch
  1176. }
  1177.  
  1178. #if defined(BI_NAMESPACE)
  1179. namespace OWL {
  1180. #endif
  1181.  
  1182. //
  1183. // Determine the object pointer by sending a GetWindowPtrMsgId message to the
  1184. // window.  When the first StdWndProc() in the subclass chain receives this
  1185. // message it returns a pointer to the object (via the thunking mechanism).
  1186. // If app is non-zero, then the process makes sure that the corresponding
  1187. // TWindow is returned.
  1188. //
  1189. TWindow* _OWLFUNC GetWindowPtr(HWND hWnd, const TApplication* app)
  1190. {
  1191.   if (!hWnd /* && ::IsWindow(hWnd) */)  // Could also check handle validity
  1192.     return 0;
  1193.  
  1194. #if defined(BI_DATA_NEAR)
  1195.   TParam2 param2 = app ? TParam2(app) : 0;
  1196. #else
  1197.   TParam2 param2 = TParam2(app);
  1198. #endif
  1199.  
  1200.   // Avoid SendMessage to cutdown the overhead & message spy tool flooding
  1201.   //
  1202.   // Under Win16, need to fallback to SendMessage when the given hWnd is owned
  1203.   // by another task. Using CallWindowProc on it would result in a bad SS
  1204.   // setup when it received the message.
  1205.   //
  1206.   // Under Win32 don't even try if it is not our process. Some Win32's will
  1207.   // return a wndProc that crashes.
  1208.   //
  1209. #if defined(BI_PLAT_WIN16)
  1210.   if (::GetWindowTask(hWnd) != ::GetCurrentTask())
  1211.     return (TWindow*)::SendMessage(hWnd, GetWindowPtrMsgId, 0, param2);
  1212. #else
  1213.   uint32 processId;
  1214.   ::GetWindowThreadProcessId(hWnd, &processId);
  1215.   if (processId != ::GetCurrentProcessId())
  1216.     return 0;
  1217. #endif
  1218.  
  1219.   WNDPROC wndProc = (WNDPROC)::GetWindowLong(hWnd, GWL_WNDPROC);
  1220.   if (!wndProc)
  1221.     return 0;
  1222.   return (TWindow*)::CallWindowProc(wndProc, hWnd, GetWindowPtrMsgId, 0, param2);
  1223. }
  1224.  
  1225. #if defined(BI_NAMESPACE)
  1226. } // namespace OWL
  1227. #endif
  1228.  
  1229. //
  1230. // Response method for an incoming WM_CREATE message
  1231. //
  1232. // Call virtual SetupWindow to give derived classes a chance to set things up
  1233. // now that we are created & have a Handle
  1234. //
  1235. int
  1236. TWindow::EvCreate(CREATESTRUCT far&)
  1237. {
  1238.   SetupWindow();
  1239.   SetFlag(wfFullyCreated);
  1240.   return (int)DefaultProcessing();
  1241. }
  1242.  
  1243. //
  1244. // Regular windows never hold focus child handles--just say no.
  1245. //
  1246. bool
  1247. TWindow::HoldFocusHWnd(HWND /*hWndLose*/, HWND /*hWndGain*/)
  1248. {
  1249.   return false;
  1250. }
  1251.  
  1252. //
  1253. // Handle WM_KILLFOCUS so that we can have a parent window hold onto our
  1254. // Handle and possibly restore focus later.
  1255. //
  1256. void
  1257. TWindow::EvKillFocus(HWND getFocus)
  1258. {
  1259.   // Follow the parent chain back until a window volunteers to hold our handle
  1260.   //
  1261.   if (IsFlagSet(wfFullyCreated)) {
  1262.     TWindow* holdWin = Parent;
  1263.     while (holdWin && !holdWin->HoldFocusHWnd(GetHandle(), getFocus))
  1264.       holdWin = holdWin->Parent;
  1265.   }
  1266.  
  1267.   DefaultProcessing();
  1268. }
  1269.  
  1270. //
  1271. // Response method for an incoming WM_SIZE message
  1272. //
  1273. // Saves the normal size of the window in Attr.
  1274. // Also calls the SetPageSize() and SetBarRange() methods of the TWindow's
  1275. // scroller, if it has been constructed.
  1276. //
  1277. void
  1278. TWindow::EvSize(uint sizeType, TSize&)
  1279. {
  1280.   static bool inScroller = false;
  1281.   if (!inScroller && Scroller && sizeType != SIZE_MINIMIZED) {
  1282.     inScroller = true;
  1283.     Scroller->SetPageSize();
  1284.     Scroller->SetSBarRange();
  1285.     inScroller = false;
  1286.   }
  1287.  
  1288.   if (sizeType == SIZE_RESTORED) {
  1289.     TRect  wndRect;
  1290.     GetWindowRect(wndRect);
  1291.  
  1292.     Attr.W = wndRect.Width();
  1293.     Attr.H = wndRect.Height();
  1294.   }
  1295.  
  1296.   // Added Owl functionality: notify parent of a resize in case it wants to
  1297.   // adjust accordingly
  1298.   //
  1299.   if (Parent && !(GetExStyle() & WS_EX_NOPARENTNOTIFY))
  1300.     Parent->SendMessage(WM_PARENTNOTIFY, WM_SIZE, TParam2(GetHandle()));
  1301.  
  1302.   DefaultProcessing();
  1303. }
  1304.  
  1305. //
  1306. // Save the normal position of the window.
  1307. // If IsIconic() or IsZoomed() ignore the position since it does not reflect
  1308. // the normal state
  1309. //
  1310. void
  1311. TWindow::EvMove(TPoint&)
  1312. {
  1313.   if (!IsIconic() && !IsZoomed()) {
  1314.     TRect wndRect;
  1315.  
  1316.     GetWindowRect(wndRect);
  1317.  
  1318.     if ((GetWindowLong(GWL_STYLE) & WS_CHILD) == WS_CHILD && Parent &&
  1319.          Parent->GetHandle())
  1320.       Parent->ScreenToClient(wndRect.TopLeft());
  1321.  
  1322.     Attr.X = wndRect.left;
  1323.     Attr.Y = wndRect.top;
  1324.   }
  1325.  
  1326.   DefaultProcessing();
  1327. }
  1328.  
  1329. //
  1330. // Handles WM_COMPAREITEM message (for owner draw controls) by forwarding
  1331. // message to control itself
  1332. //
  1333. TResult
  1334. TWindow::EvCompareItem(uint /*ctrlId*/, COMPAREITEMSTRUCT far& compareInfo)
  1335. {
  1336.   TWindow* win = GetWindowPtr(compareInfo.hwndItem);
  1337.   if (win)
  1338.     return win->ForwardMessage();
  1339.   return DefaultProcessing();
  1340. }
  1341.  
  1342. //
  1343. // Handles WM_DELETEITEM message (for owner draw controls) by forwarding
  1344. // message to control itself
  1345. //
  1346. void
  1347. TWindow::EvDeleteItem(uint /*ctrlId*/, DELETEITEMSTRUCT far& deleteInfo)
  1348. {
  1349.   TWindow* win = GetWindowPtr(deleteInfo.hwndItem);
  1350.   if (deleteInfo.hwndItem != GetHandle() && win)
  1351.     win->ForwardMessage();
  1352.   else
  1353.     DefaultProcessing();
  1354. }
  1355.  
  1356. //
  1357. // Handles WM_DRAWITEM message (for owner draw controls & menus) by forwarding
  1358. // message to control itself
  1359. //
  1360. void
  1361. TWindow::EvDrawItem(uint /*ctrlId*/, DRAWITEMSTRUCT far& drawInfo)
  1362. {
  1363.   if (drawInfo.CtlType == ODT_MENU) {
  1364.     // Could dispatch to menu...
  1365.     // TMenu* menu = ...
  1366.     // menu->DrawItem(drawInfo);
  1367.   }
  1368.   else {
  1369.     TWindow* win = GetWindowPtr(drawInfo.hwndItem);
  1370.     if (drawInfo.hwndItem != GetHandle() && win) {
  1371.       win->ForwardMessage();
  1372.       return;
  1373.     }
  1374.   }
  1375.   DefaultProcessing();
  1376. }
  1377.  
  1378. //
  1379. // Handles WM_MEASUREITEM message (for owner draw controls & menus) by
  1380. // forwarding message to control itself
  1381. //
  1382. void
  1383. TWindow::EvMeasureItem(uint ctrlId, MEASUREITEMSTRUCT far& measureInfo)
  1384. {
  1385.   if (measureInfo.CtlType == ODT_MENU) {
  1386.     // Could dispatch to menu...
  1387.     // TMenu* menu = ...
  1388.     // menu->MeasureItem(measureInfo);
  1389.   }
  1390.   else {
  1391.     HWND  hCtl = GetDlgItem(measureInfo.CtlID);  // hWnd not in struct, get
  1392.     TWindow* win = GetWindowPtr(hCtl);
  1393.  
  1394.     // If the GetWindowPtr failed, & CreationWindow is non-zero, then this
  1395.     // WM_MEASUREITEM is probably for the ctrl which is not yet thunked.
  1396.     // route the message directly to creation window.
  1397.     // NOTE: Msg. may be sent before OWL has had a chance to thunk the ctrl.
  1398.     //
  1399.     if (!win) {
  1400.       TWindow* creationWindow = GetCreationWindow();
  1401.       if (creationWindow) {
  1402.         if (creationWindow != this)   // Don't cause a recursion loop
  1403.           win = creationWindow;
  1404.       }
  1405.       else
  1406.         win = ChildWithId(ctrlId);
  1407.     }
  1408.     if (win) {
  1409.       win->SendMessage(WM_MEASUREITEM, ctrlId, TParam2(&measureInfo));
  1410.       return;
  1411.     }
  1412.   }
  1413.   DefaultProcessing();
  1414. }
  1415.  
  1416. #if defined(BI_PLAT_WIN32)
  1417. //
  1418. // Process Win32 Control Color messages by redispatching to Win16-like member
  1419. // function.
  1420. //
  1421. TResult
  1422. TWindow::EvWin32CtlColor(TParam1 param1, TParam2 param2)
  1423. {
  1424.   int  ctlType = GetCurrentEvent().Message - WM_CTLCOLORMSGBOX;
  1425.  
  1426.   CHECK(ctlType >= CTLCOLOR_MSGBOX && ctlType <= CTLCOLOR_STATIC);
  1427.  
  1428.   TEventInfo  eventInfo(WM_CTLCOLOR);
  1429.  
  1430.   if (Find(eventInfo)) {
  1431.     typedef HBRUSH(GENERIC::*CTL_COLOR_PMF)(HDC, HWND, uint);
  1432.  
  1433.     CTL_COLOR_PMF&  pmf = (CTL_COLOR_PMF&)(eventInfo.Entry->Pmf);
  1434.  
  1435.     return (TResult)(eventInfo.Object->*pmf)((HDC)param1, (HWND)param2, ctlType);
  1436.   }
  1437.   return DefWindowProc(GetCurrentEvent().Message, param1, param2);
  1438. }
  1439. #endif
  1440.  
  1441. //
  1442. // Dispatches scroll messages as if they were Command messages.
  1443. //
  1444. void
  1445. TWindow::DispatchScroll(uint scrollCode, uint /*thumbPos*/, HWND hWndCtrl)
  1446. {
  1447.   if (hWndCtrl) {
  1448.     TWindow* win = GetWindowPtr(hWndCtrl);
  1449.     if (win)
  1450.       win->ForwardMessage();
  1451.  
  1452.     // Adjust "CurrentEvent" to allow DefaultProcessing to work
  1453.     //
  1454.     uint16 id = (uint16)::GetDlgCtrlID(hWndCtrl);
  1455.     TCurrentEvent& currentEvent = GetCurrentEvent();
  1456.     currentEvent.Message = WM_COMMAND;
  1457. #if defined(BI_PLAT_WIN16)
  1458.       currentEvent.Param1 = id;
  1459.       currentEvent.Param2 = MkParam2(uint16(hWndCtrl), scrollCode);
  1460. #else
  1461.       currentEvent.Param1 = MkParam1(id, scrollCode);
  1462.       currentEvent.Param2 = TParam2(hWndCtrl);
  1463. #endif
  1464.  
  1465.     EvCommand(id, hWndCtrl, scrollCode);
  1466.     return;
  1467.   }
  1468.   DefaultProcessing();
  1469. }
  1470.  
  1471. //
  1472. // Response method for an incoming WM_HSCROLL message
  1473. //
  1474. // If the message is from a scrollbar control, calls DispatchScroll()
  1475. // otherwise passes the message to the TWindow's scroller if it has been
  1476. // constructed, else calls DefaultProcessing()
  1477. //
  1478. // Assumes, because of a Windows bug, that if the window has the scrollbar
  1479. // style, it will not have scrollbar controls
  1480. //
  1481. void
  1482. TWindow::EvHScroll(uint scrollCode, uint thumbPos, HWND hWndCtl)
  1483. {
  1484.   if (!(GetWindowLong(GWL_STYLE) & WS_HSCROLL))
  1485.     DispatchScroll(scrollCode, thumbPos, hWndCtl);  // from scrollbar control
  1486.  
  1487.   else if (Scroller)
  1488.     Scroller->HScroll(scrollCode, thumbPos);
  1489.  
  1490.   else
  1491.     DefaultProcessing();
  1492. }
  1493.  
  1494. //
  1495. // Response method for an incoming WM_VSCROLL message
  1496. //
  1497. // If the message is from a scrollbar control, calls DispatchScroll()
  1498. // otherwise passes the message to the TWindow's scroller if it has been
  1499. // constructed, else calls DefaultProcessing()
  1500. //
  1501. // Assumes, because of a Windows bug, that if the window has the scrollbar
  1502. // style, it will not have scrollbar controls
  1503. //
  1504. void
  1505. TWindow::EvVScroll(uint scrollCode, uint thumbPos, HWND hWndCtl)
  1506. {
  1507.   if (!(GetWindowLong(GWL_STYLE) & WS_VSCROLL))
  1508.     DispatchScroll(scrollCode, thumbPos, hWndCtl);
  1509.  
  1510.   else if (Scroller)
  1511.     Scroller->VScroll(scrollCode, thumbPos);
  1512.  
  1513.   else
  1514.     DefaultProcessing();
  1515. }
  1516.  
  1517. //
  1518. // Response method for an incoming WM_ERASEBKGND message
  1519. //
  1520. bool
  1521. TWindow::EvEraseBkgnd(HDC hDC)
  1522. {
  1523.   // If color is set, we'll handle erasing (or doing nothing) here
  1524.   //
  1525.   if (BkgndColor != TColor::None) {
  1526.  
  1527.     // If a color is set, blt out a rectangle of it, else don't erase & let
  1528.     // paint handle background
  1529.     //
  1530.     if (BkgndColor != TColor::Transparent) {
  1531.       TDC dc(hDC);
  1532.       TBrush bkBrush(BkgndColor);
  1533.       dc.SelectObject(bkBrush);
  1534.       dc.SetBkColor(BkgndColor);
  1535.       dc.PatBlt(GetClientRect());
  1536.       dc.RestoreBrush();
  1537.     }
  1538.     return true;
  1539.   }
  1540.  
  1541.   // No color set, use default class brush
  1542.   //
  1543.   return (bool)DefaultProcessing();
  1544. }
  1545.  
  1546. //
  1547. // Respond to WM_CTLCOLOR if we have a bkgnd color set & pass that to the
  1548. // control
  1549. //
  1550. HBRUSH
  1551. TWindow::EvCtlColor(HDC hDC, HWND /*hWndChild*/, uint ctlType)
  1552. {
  1553.   // If a bkgnd color is set, then setup the hdc's bkcolor and return a
  1554.   // brush for the child to use
  1555.   //
  1556.   if (BkgndColor != TColor::None && BkgndColor != TColor::Transparent
  1557.       && ctlType != CTLCOLOR_EDIT && ctlType != CTLCOLOR_LISTBOX)
  1558.   {
  1559.     ::SetBkColor(hDC, BkgndColor);
  1560.     return TBrush(BkgndColor);  // HBRUSH will stay in cache
  1561.   }
  1562.  
  1563.   // No color set, use default windows behavior
  1564.   //
  1565.   return (HBRUSH)DefaultProcessing();
  1566. }
  1567.  
  1568. //
  1569. // Response method for an incoming WM_PAINT message
  1570. //
  1571. // Calls Paint(), performing Windows-required paint setup and cleanup before
  1572. // and after. if the TWindow has a TScroller, also calls its BeginView() and
  1573. // EndView() methods before and after call to Paint()
  1574. //
  1575. void
  1576. TWindow::EvPaint()
  1577. {
  1578.   if (IsFlagSet(wfAlias))
  1579.     DefaultProcessing();  // use application-defined wndproc
  1580.  
  1581.   else {
  1582.     TPaintDC dc(*this);
  1583.     TRect&   rect = *(TRect*)&dc.Ps.rcPaint;
  1584.  
  1585.     if (Scroller)
  1586.       Scroller->BeginView(dc, rect);
  1587.  
  1588.     Paint(dc, dc.Ps.fErase, rect);
  1589.  
  1590.     if (Scroller)
  1591.       Scroller->EndView();
  1592.   }
  1593. }
  1594.  
  1595. //
  1596. // Redraws the contents of the TWindow after a WM_PAINT message
  1597. // is received
  1598. //
  1599. // Placeholder for descendant object types to redefine
  1600. //
  1601. void
  1602. TWindow::Paint(TDC&, bool /*erase*/, TRect&)
  1603. {
  1604. }
  1605.  
  1606. //
  1607. // Response method for an incoming WM_SETCURSOR message
  1608. //
  1609. // If a cursor has been set for this window, & the mouse is over the
  1610. // client area, set the cursor
  1611. //
  1612. bool
  1613. TWindow::EvSetCursor(HWND hWndCursor, uint hitTest, uint /*mouseMsg*/)
  1614. {
  1615.   if (hWndCursor == GetHandle() && hitTest == HTCLIENT && HCursor) {
  1616.     ::SetCursor(HCursor);
  1617.     return true;
  1618.   }
  1619.   return (bool)DefaultProcessing();
  1620. }
  1621.  
  1622. //
  1623. // Response method for an incoming WM_LBUTTONDOWN message
  1624. //
  1625. // If the TWindow's Scroller has been constructed and if auto-scrolling
  1626. // has been requested, captures mouse input, loops until a WM_LBUTTONUP
  1627. // message comes in calling the Scroller's AutoScroll method, and then
  1628. // releases capture on mouse input.
  1629. // Will also break if a WM_MOUSEMOVE comes in without the left button down
  1630. // indicating a lost WM_LBUTTONUP
  1631. //
  1632. void
  1633. TWindow::EvLButtonDown(uint /*modKeys*/, TPoint& /*pt*/)
  1634. {
  1635.   if (Scroller && Scroller->IsAutoMode()) {
  1636.     MSG  loopMsg;
  1637.  
  1638.     loopMsg.message = 0;
  1639.     SetCapture();
  1640.  
  1641.     while (loopMsg.message != WM_LBUTTONUP &&
  1642.           (loopMsg.message != WM_MOUSEMOVE || (loopMsg.wParam&MK_LBUTTON))) {
  1643.       if (::PeekMessage(&loopMsg, 0, 0, 0, PM_REMOVE)) {
  1644.         ::TranslateMessage(&loopMsg);
  1645.         ::DispatchMessage(&loopMsg);
  1646.       }
  1647.  
  1648.       Scroller->AutoScroll();
  1649.     }
  1650.  
  1651.     ReleaseCapture();
  1652.     GetApplication()->ResumeThrow();
  1653.   }
  1654.  
  1655.   DefaultProcessing();
  1656. }
  1657.  
  1658. #if defined(BI_NAMESPACE)
  1659. namespace OWL {
  1660. #endif 
  1661.  
  1662. //
  1663. //
  1664. //
  1665. void
  1666. DoEnableAutoCreate(TWindow* win, void* /*retVal*/)
  1667. {
  1668.   if (win->GetHandle())
  1669.     win->EnableAutoCreate();
  1670. }
  1671.  
  1672. #if defined(BI_NAMESPACE)
  1673. } // namespace OWL
  1674. #endif 
  1675.  
  1676. //
  1677. // Destroys an MS-Windows element associated with the TWindow.
  1678. // First, sets the wfAutoCreate flag to ON for each of the windows in the
  1679. // TWindow's ChildList to allow later re-creation.
  1680. //
  1681. void
  1682. TWindow::Destroy(int ret)
  1683. {
  1684.   if (GetHandle()) {
  1685.     ForEach(DoEnableAutoCreate, 0);
  1686.  
  1687.     if (IsFlagSet(wfModalWindow)) {
  1688.       GetApplication()->EndModal(ret);
  1689.       ClearFlag(wfModalWindow);
  1690.       if (Parent && Parent->GetHandle())
  1691.         Parent->SetFocus();
  1692.     }
  1693.  
  1694.     if (::DestroyWindow(GetHandle()))
  1695.       SetHandle(0);
  1696.  
  1697.     GetApplication()->ResumeThrow();
  1698.     WARNX(OwlWin, GetHandle(), 0, "::DestroyWindow(" << (uint)GetHandle() << ") failed");
  1699.   }
  1700. }
  1701.  
  1702. //
  1703. // Specifies registration attributes for the MS-Windows window class of the
  1704. // TWindow, allowing instances of TWindow to be registered
  1705. //
  1706. // Sets the fields of the passed WNDCLASS parameter to the default attributes
  1707. // appropriate for a TWindow
  1708. //
  1709. // Register unique classes for windows that want system background colors so
  1710. // that full-drag erasing uses the right color (NT fails to let window erase
  1711. // itself)
  1712. //
  1713. void
  1714. TWindow::GetWindowClass(WNDCLASS& wndClass)
  1715. {
  1716.   wndClass.cbClsExtra = 0;
  1717.   wndClass.cbWndExtra = 0;
  1718.   wndClass.hInstance = *GetModule();
  1719.   wndClass.hIcon = 0;
  1720.   wndClass.hCursor = ::LoadCursor(0, IDC_ARROW);
  1721.  
  1722.   if (BkgndColor.IsSysColor() &&
  1723.       BkgndColor != TColor::None && BkgndColor != TColor::Transparent)
  1724.     wndClass.hbrBackground = HBRUSH(BkgndColor.Index()+1);
  1725.   else
  1726.     wndClass.hbrBackground = HBRUSH(COLOR_WINDOW+1);
  1727.  
  1728.   wndClass.lpszMenuName = 0;
  1729.   wndClass.lpszClassName = GetClassName();
  1730.   wndClass.style = CS_DBLCLKS;
  1731.   wndClass.lpfnWndProc = InitWndProc;
  1732. }
  1733.  
  1734. //
  1735. // Return the classname for a generic owl window. Assume instance private class
  1736. // registration so that no instance mangling is needed.
  1737. //
  1738. // Register unique classnames for windows that want system background colors
  1739. //
  1740. char far*
  1741. TWindow::GetClassName()
  1742. {
  1743.   static const char baseClassName[] = "OWL_Window";
  1744.  
  1745.   if (BkgndColor.IsSysColor() &&
  1746.       BkgndColor != TColor::None && BkgndColor != TColor::Transparent) {
  1747.     static char namebuff[sizeof baseClassName + 1 + 10 + 1 + 4];
  1748.     sprintf(namebuff, "%s:%X", baseClassName, BkgndColor.Index());
  1749.     return namebuff;
  1750.   }
  1751.   return CONST_CAST(char far*, baseClassName);  // cast for old non-const type
  1752. }
  1753.  
  1754. //
  1755. // Set this window's accelerator table, performing the load also if this window
  1756. // is already created
  1757. //
  1758. void
  1759. TWindow::SetAcceleratorTable(TResId resId)
  1760. {
  1761.   Attr.AccelTable = resId;
  1762.   if (GetHandle())
  1763.     LoadAcceleratorTable();
  1764.   else
  1765.     HAccel = 0;
  1766. }
  1767.  
  1768. //
  1769. // Load the accelerator table indicated in Attr from this window's module's
  1770. // resource.
  1771. //
  1772. void
  1773. TWindow::LoadAcceleratorTable()
  1774. {
  1775.   if (Attr.AccelTable) {
  1776.     HAccel = GetModule()->LoadAccelerators(Attr.AccelTable);
  1777.     WARNX(OwlWin, !HAccel, 0,
  1778.           "Unable to load accelerators " << Attr.AccelTable
  1779.           << " from " << *GetModule());
  1780.   }
  1781. }
  1782.  
  1783. //
  1784. // Perform MS Windows HWND creation and keep hwnd in Handle member
  1785. //
  1786. void
  1787. TWindow::PerformCreate(int menuOrId)
  1788. {
  1789.   PRECONDITION(GetModule());
  1790.   HWND hwnd = ::CreateWindowEx(Attr.ExStyle,
  1791.                                GetClassName(),
  1792.                                Title,
  1793.                                Attr.Style,
  1794.                                Attr.X, Attr.Y, Attr.W, Attr.H,
  1795.                                Parent ? Parent->GetHandle() : 0,
  1796.                                REINTERPRET_CAST(HMENU,menuOrId),
  1797.                                *GetModule(),
  1798.                                Attr.Param);
  1799.   SetHandle(hwnd);
  1800.  
  1801. #if defined(__WARN)
  1802.   char modName[_MAX_PATH];
  1803.   GetModule()->GetModuleFileName(modName, _MAX_PATH);
  1804.   uint parent = Parent ? uint(Parent->GetHandle()) : 0;
  1805.   WARNX(OwlWin, !hwnd, 0, "CreateWindowEx failed: " <<\
  1806.                 "Class: \"" << string(GetClassName()) << "\", " <<\
  1807.                 "Title: \"" << string(Title) << "\", " <<\
  1808.                 "Style: " << Attr.Style << ", " <<\
  1809.                 "Parent: " << parent << ", "        <<\
  1810.                 "Module: \"" << modName);
  1811. #endif
  1812. }
  1813.  
  1814. //
  1815. // Associates an MS Windows interface element with the TWindow object,
  1816. // after creating the interface element if not already created
  1817. //
  1818. // When creating an element, uses the creation attributes previously set in
  1819. // the Attr data field (simply associates the TWindow with an already
  1820. // created interface element if the "FromResource" flag is set)
  1821. //
  1822. // Since this member function now throws an exception on error, it always
  1823. // returns true.
  1824. //
  1825. bool
  1826. TWindow::Create()
  1827. {
  1828.   if (GetHandle())
  1829.     return true;
  1830.  
  1831.   int  menuOrId = 0;
  1832.  
  1833.   DisableAutoCreate();
  1834.  
  1835.   // If this is the main window, make sure it is treated as one by the shell
  1836.   //
  1837.   if (IsFlagSet(wfMainWindow))
  1838.     ModifyExStyle(0, WS_EX_APPWINDOW);
  1839.  
  1840.   if (IsFlagSet(wfFromResource))
  1841.     SetHandle(Parent ? Parent->GetDlgItem(Attr.Id) : 0);  // Windows already created it
  1842.  
  1843.   else if (Register()) {
  1844.     ::SetCreationWindow(this);
  1845.  
  1846.     LoadAcceleratorTable();
  1847.  
  1848.     if (Attr.Menu) {
  1849.       menuOrId = (int)GetModule()->LoadMenu(Attr.Menu);
  1850.       WARNX(OwlWin, !menuOrId, 0, "Unable to load menu: " << Attr.Menu <<
  1851.             " from " << *GetModule());
  1852.     }
  1853.     else
  1854.       menuOrId = Attr.Id;
  1855.  
  1856.     PerformCreate(menuOrId);
  1857.     GetApplication()->ResumeThrow();
  1858.   }
  1859.   else
  1860.     TXWindow::Raise(this, IDS_CLASSREGISTERFAIL);
  1861.  
  1862.   if (!GetHandle()) {
  1863.     if (Attr.Menu)  // && !IsFlagSet(wfFromResource) ?
  1864.       DestroyMenu(HMENU(menuOrId));
  1865.  
  1866.     TXWindow::Raise(this, IDS_WINDOWCREATEFAIL);
  1867.   }
  1868.  
  1869.   // Here we have a non-thunked handle. This may be caused by two scenarios:
  1870.   // 1. Predefined-class (non-owl) windows.
  1871.   // 2. OWL controls which were created from resource [Although these
  1872.   //    are registered with InitWndProc, they did not get thunked since
  1873.   //    'CreationWindow' was not set when they received their first messages].
  1874.   //
  1875.   if (!GetWindowPtr(GetHandle())) {
  1876.  
  1877.     // Grab the state info.
  1878.     //
  1879.     GetWindowTextTitle();
  1880.     GetHWndState();
  1881.  
  1882.     // If it's a 'predefinedClass' window, subclass it
  1883.     //
  1884.     if (GetWindowProc() != InitWndProc) {
  1885.       SubclassWindowFunction();
  1886.  
  1887.       // Reset the 'CreationWindow' pointer [if necessary]
  1888.       //
  1889.       if (::GetCreationWindow() == this)
  1890.         ::SetCreationWindow(0);
  1891.  
  1892.       // Set status flag [since we missed EvCreate]
  1893.       //
  1894.       SetFlag(wfPredefinedClass|wfFullyCreated);
  1895.     }
  1896.     else {
  1897.       // This window's WNDPROC is 'InitWndProc' - However, it has not
  1898.       // been thunked since 'CreationWindow' was not set when it received
  1899.       // its first messages [it was probably created from a resource but
  1900.       // registered by OWL]. We'll set 'CreationWindow' and send a dummy
  1901.       // message to allow thunking to take place
  1902.       //
  1903.       if (!::GetCreationWindow())
  1904.         ::SetCreationWindow(this);
  1905.       SendMessage(WM_USER+0x4000, 0, 0);
  1906.  
  1907.       // Update flags
  1908.       //
  1909.       SetFlag(wfFullyCreated);
  1910.     }
  1911.  
  1912.     // Invoke SetupWindow since 'EvCreate' was missed..
  1913.     //
  1914.     SetupWindow();
  1915.   }
  1916.   return true;
  1917. }
  1918.  
  1919. //
  1920. // Creates the underlying HWND and makes modal with the help
  1921. // of TApplication's BeginModal support.
  1922. //
  1923. int
  1924. TWindow::Execute()
  1925. {
  1926.   return DoExecute();
  1927. }
  1928.  
  1929. //
  1930. // Do actual modal execution using the Begin/End Modal
  1931. // support of TApplication.
  1932. // NOTE: Defaults to 'TASKMODAL'
  1933. //
  1934. int
  1935. TWindow::DoExecute()
  1936. {
  1937.   // Attempting to go modal when one's a child is indicative of
  1938.   // suicidal tendencies!!
  1939.   //
  1940.   PRECONDITION((GetStyle() & WS_CHILD) == 0);
  1941.  
  1942.   if (GetApplication()) {
  1943.     if (Create()) {
  1944.       SetFlag(wfModalWindow);
  1945.       return GetApplication()->BeginModal(this, MB_TASKMODAL);
  1946.     }
  1947.   }
  1948.   return -1;
  1949. }
  1950.  
  1951. //
  1952. // Performs setup following creation of an associated MS-Windows window.
  1953. // Iterates through the TWindow's ChildList, attempting to create
  1954. // an associated MS-Windows interface element for each child window
  1955. // object in the list (a child's Create method is not called if its
  1956. // wfAutoCreate flag is not set)
  1957. //
  1958. // Calls TransferData to transfer data for its children for whom data transfer
  1959. // is enabled.
  1960. //
  1961. // If the receiver has a TScroller object, calls the scroller's SetBarRange()
  1962. // method.
  1963. //
  1964. // Can be redefined in derived classes to perform additional special
  1965. // initialization that requires an HWND.
  1966. //
  1967. void
  1968. TWindow::SetupWindow()
  1969. {
  1970.   TRACEX(OwlWin, 1, "TWindow::SetupWindow() @" << (void*)this << *this);
  1971.  
  1972.   // Update scrollbar - if a scroller was attached to the window
  1973.   //
  1974.   if (Scroller)
  1975.     Scroller->SetSBarRange();
  1976.  
  1977.   // NOTE: CreateChildren will throw a TXWindow exception if one of the
  1978.   //       child objects could not be created.
  1979.   //
  1980.   CreateChildren();
  1981.  
  1982.   // Initialize children specified data
  1983.   //
  1984.   TransferData(tdSetData);
  1985. }
  1986.  
  1987. //
  1988. // Always called just before Handle goes away to give derived classes a
  1989. // chance to cleanup native Handle related resources.
  1990. //
  1991. void
  1992. TWindow::CleanupWindow()
  1993. {
  1994.   TRACEX(OwlWin, 1, "TWindow::CleanupWindow() @" << (void*)this << *this);
  1995. }
  1996.  
  1997. //
  1998. // Transfer window 'data' to/from the passed data buffer.  Used to initialize
  1999. // windows and get data in or out of them.
  2000. //
  2001. // The direction passed specifies whether data is to be read from or written
  2002. // to the passed buffer, or whether the data element size is simply to be
  2003. // returned
  2004. //
  2005. // The return value is the size (in bytes) of the transfer data.  this method
  2006. // recursively calls transfer on all its children that have wfTransfer set.
  2007. //
  2008. #include <pshpack1.h>
  2009.  
  2010. struct TTransferIterInfo {
  2011.   void*               Data;
  2012.   TTransferDirection  Direction;
  2013. };
  2014.  
  2015. #include <poppack.h>
  2016.  
  2017. static void transferDatchild(TWindow* child, TTransferIterInfo* info) {
  2018.   if (child->IsFlagSet(wfTransfer))
  2019.     info->Data = (char*)info->Data + child->Transfer(info->Data, info->Direction);
  2020. }
  2021.  
  2022. //
  2023. //
  2024. //
  2025. uint
  2026. TWindow::Transfer(void* buffer, TTransferDirection direction)
  2027. {
  2028.   if (buffer) {
  2029.     TTransferIterInfo info = { buffer, direction };
  2030.     ForEach((TActionFunc)transferDatchild, &info);
  2031.     return (char near*)info.Data - (char near*)buffer;
  2032.   }
  2033.   return 0;
  2034. }
  2035.  
  2036. //
  2037. // Transfers data between the TWindow's data buffer and the child
  2038. // windows in its ChildList (data is not transfered between any child
  2039. // windows whose wfTransfer flag is not set)
  2040. //
  2041. void
  2042. TWindow::TransferData(TTransferDirection direction)
  2043. {
  2044.   if (TransferBuffer)
  2045.     Transfer(TransferBuffer, direction);
  2046. }
  2047.  
  2048. //
  2049. // Registers the TWindow's MS-Windows, if not already registered
  2050. //
  2051. bool
  2052. TWindow::Register()
  2053. {
  2054.   // Only check for globally registered classes if not under NT or WoW box,
  2055.   // since NT treats a 0 hInstance completely differently than Windows.
  2056.   //
  2057. #if defined(BI_PLAT_WIN32)
  2058.   static bool checkGlobal = !TSystem::IsNT();
  2059. #else
  2060.   static bool checkGlobal = !TSystem::IsWoW();
  2061. #endif
  2062.  
  2063.   WNDCLASS  windowClass;
  2064.   bool gc;
  2065.   if (checkGlobal)
  2066.     gc = TUser::GetClassInfo(0, GetClassName(), &windowClass) != 0;
  2067.   else
  2068.     gc = false;
  2069.  
  2070.   // If the wndclass is not yet registered, call GetWindowClass() to let our
  2071.   // derived class fill in the appropriate info. If the class is still then not
  2072.   // registered, then make it so.
  2073.   //
  2074.   if (!gc && !GetModule()->GetClassInfo(GetClassName(), &windowClass)) {
  2075.     GetWindowClass(windowClass);
  2076.     WNDCLASS dummy;
  2077.     if (!GetModule()->GetClassInfo(GetClassName(), &dummy))
  2078.       return ::RegisterClass(&windowClass);
  2079.   }
  2080.  
  2081.   return true;
  2082. }
  2083.  
  2084. //
  2085. // Returns a bool indicating whether or not it is Ok to close the TWindow
  2086. //
  2087. // Iterates through the TWindow's ChildList, calling the CanClose()
  2088. // method of each
  2089. //
  2090. // Returns false if any of the child windows returns false
  2091. //
  2092.  
  2093. static bool cannotClose(TWindow* win, void*) {
  2094.   return win->GetHandle() && !win->CanClose();
  2095. }
  2096.  
  2097. //
  2098. //
  2099. //
  2100. bool
  2101. TWindow::CanClose()
  2102. {
  2103.   return !FirstThat(cannotClose);
  2104. }
  2105.  
  2106. //
  2107. // Destroys the associated MS-Windows interface element after determining that
  2108. // it is Ok to do so
  2109. //
  2110. // If the TWindow is the main window of the application, calls the CanClose()
  2111. // method of the application, else calls this->CanClose(), before calling
  2112. // Destroy()
  2113. //
  2114. void
  2115. TWindow::CloseWindow(int retVal)
  2116. {
  2117.   bool  willClose;
  2118.  
  2119.   if (IsFlagSet(wfMainWindow))
  2120.     willClose = GetApplication()->CanClose();
  2121.  
  2122.   else
  2123.     willClose = CanClose();
  2124.  
  2125.   if (willClose)
  2126.     Destroy(retVal);
  2127. }
  2128.  
  2129. //
  2130. // The default response to a WM_CLOSE message is to call CloseWindow()
  2131. // and then have the window deleted if the Handle was really destroyed.
  2132. //
  2133. void
  2134. TWindow::EvClose()
  2135. {
  2136.   if (IsFlagSet(wfAlias))
  2137.     DefaultProcessing();
  2138.  
  2139.   else {
  2140.     CloseWindow();
  2141.     if (!GetHandle() && IsFlagSet(wfDeleteOnClose))
  2142.       GetApplication()->Condemn(this);  // Assumes delete
  2143.   }
  2144. }
  2145.  
  2146. //
  2147. // Responds to an incoming WM_DESTROY message
  2148. //
  2149. // Calls CleanupWindow() to let derived classes cleanup
  2150. // Clears the wfFullyCreated flag since this window is no longer fully created
  2151. //
  2152. // If the TWindow is the application's main window posts a 'quit' message to
  2153. // end the application, unless already in ~TApplication() (MainWindow == 0)
  2154. //
  2155. void
  2156. TWindow::EvDestroy()
  2157. {
  2158.   ClearFlag(wfFullyCreated);
  2159.   CleanupWindow();
  2160.  
  2161.   if (!IsFlagSet(wfAlias)) {
  2162.     if (IsFlagSet(wfMainWindow) && GetApplication()->IsRunning())
  2163.       ::PostQuitMessage(0);
  2164.   }
  2165.  
  2166.   DefaultProcessing();
  2167. }
  2168.  
  2169. //
  2170. // Responds to an incoming WM_NCDESTROY message, the last message
  2171. // sent to an MS-Windows interface element
  2172. //
  2173. // Sets the Handle data member of the TWindow to zero to indicate that an
  2174. // interface element is no longer associated with the object
  2175. //
  2176. void
  2177. TWindow::EvNCDestroy()
  2178. {
  2179.   DefaultProcessing();
  2180.   SetHandle(0);
  2181. }
  2182.  
  2183. //
  2184. // Respond to Windows attempt to close down. Determines if this app or window
  2185. // is ready to close.
  2186. //
  2187. bool
  2188. TWindow::EvQueryEndSession()
  2189. {
  2190.   if (IsFlagSet(wfAlias))
  2191.     return (bool)DefaultProcessing();
  2192.  
  2193.   else if (IsFlagSet(wfMainWindow))
  2194.     return GetApplication()->CanClose();
  2195.  
  2196.   else
  2197.     return CanClose();
  2198. }
  2199.  
  2200. //
  2201. // Windows is shutting down.
  2202. //
  2203. void
  2204. TWindow::EvEndSession(bool, bool)
  2205. {
  2206.   DefaultProcessing();    
  2207. }
  2208.  
  2209.  
  2210. //
  2211. // Handle message posted to us by a control needing assistance in dealing with
  2212. // invalid inputs
  2213. //
  2214. void
  2215. TWindow::EvChildInvalid(HWND handle)
  2216. {
  2217.   PRECONDITION(handle);
  2218.  
  2219.   ::SendMessage(handle, WM_CHILDINVALID, 0, 0);
  2220. }
  2221.  
  2222. //----------------------------------------------------------------------------
  2223. // Non-virtuals
  2224. //
  2225.  
  2226. void
  2227. TWindow::AttachHandle(HWND handle)
  2228. {
  2229.   ClearFlag(wfDetached);
  2230.   ::FreeInstanceThunk(Thunk);
  2231.   Thunk = 0;
  2232.   Init(handle, GetModule());
  2233. }
  2234.  
  2235.  
  2236. void
  2237. TWindow::DetachHandle()
  2238. {
  2239.   // NOTE: This is by no means a complete way of detaching the window...
  2240.   //       The following is logic allows Delphi/OWL interaction..
  2241.   //
  2242.   ClearFlag(wfFullyCreated);
  2243.   SetHandle(0);
  2244.   SetFlag(wfDetached);
  2245. }
  2246.  
  2247.  
  2248. //
  2249. //
  2250. //
  2251. unsigned
  2252. TWindow::NumChildren() const
  2253. {
  2254.   return IndexOf(ChildList) + 1;
  2255. }
  2256.  
  2257. //
  2258. // Walks over children and assigns a z-order index to the ZOrder member
  2259. //
  2260. void
  2261. TWindow::AssignZOrder()
  2262. {
  2263.   TWindow*  wnd;
  2264.   HWND   curWindow = GetHandle();
  2265.  
  2266.   if (curWindow) {
  2267.     curWindow = ::GetWindow(curWindow, GW_CHILD);
  2268.  
  2269.     if (curWindow) {
  2270.       int  i = 1;
  2271.  
  2272.       for (curWindow = ::GetWindow(curWindow, GW_HWNDLAST);
  2273.            curWindow;
  2274.            curWindow = ::GetWindow(curWindow, GW_HWNDPREV))
  2275.       {
  2276.         wnd = GetWindowPtr(curWindow);
  2277.  
  2278.         if (wnd)
  2279.           wnd->ZOrder = (uint16)i++;
  2280.       }
  2281.     }
  2282.   }
  2283. }
  2284.  
  2285. //
  2286. // The private field ZOrder is used to ensure the Z-order is
  2287. // consistent through read and write of the object.
  2288. //
  2289. // When the object is written, parent->AssignZOrder will fill in this value
  2290. //
  2291. // ZOrder ranges from 1 to N where N is the number of objects and the top one.
  2292. // A ZOrder value of 0 means that the Z-ordering has not be recoreded.
  2293. //
  2294. bool
  2295. TWindow::OrderIsI(TWindow* win, void* position)
  2296. {
  2297.   return win->ZOrder == *(int*)position;
  2298. }
  2299.  
  2300. //
  2301. // Returns true if the child was supposed to be created but couldn't be
  2302. //
  2303. static bool
  2304. cantCreate(TWindow* win, void*)
  2305. {
  2306.   // If child is already created, then no need to re-create it.
  2307.   //
  2308.   if (win->GetHandle()) {
  2309.     return false;
  2310.   }
  2311.  
  2312.   bool autoCreate = win->IsFlagSet(wfAutoCreate);
  2313.  
  2314.   WARNX(OwlWin, !autoCreate, 0,
  2315.         "Child window(Id=" << win->GetId() << ") not autocreated");
  2316.   if (!autoCreate)
  2317.     return false;
  2318.  
  2319.   // This call will only fail if a user-defined Create() returns false. Owl's
  2320.   // Creates always throw exceptions.
  2321.   //
  2322.   if (!win->Create())
  2323.     return true;
  2324.  
  2325.   // Get & set the window text for the child if it is iconic.
  2326.   //
  2327.   if (win->IsIconic()) {
  2328.     int    textLen = win->GetWindowTextLength();
  2329.     char*  text = new char[textLen + 1];
  2330.  
  2331.     win->GetWindowText(text, textLen + 1);
  2332.     win->SetWindowText(text);
  2333.     delete[] text;
  2334.   }
  2335.   return false;
  2336. }
  2337.  
  2338. //
  2339. // Create the children of the object.  Returns true if all the windows
  2340. // were successfully created.
  2341. // NOTE: Throws an exception (TXWindow) if a child object could not be
  2342. //       created.
  2343. //
  2344. bool
  2345. TWindow::CreateChildren()
  2346. {
  2347.   // Create children first to restore creation order
  2348.   //
  2349.   TWindow* childFailed = FirstThat(cantCreate);
  2350.   if (childFailed) {
  2351.     TXWindow::Raise(childFailed, IDS_CHILDCREATEFAIL);
  2352.   }
  2353.  
  2354.   // Restore Z-ordering for children that have Z-ordering recorded
  2355.   //
  2356.   HWND above = HWND_TOP;
  2357.   for (int top = NumChildren(); top; top--) {
  2358.     TWindow* wnd = FirstThat(&TWindow::OrderIsI, &top);
  2359.     if (wnd) {
  2360.       wnd->SetWindowPos(above, 0,0,0,0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
  2361.       above = wnd->GetHandle();
  2362.     }
  2363.   }
  2364.   return true;
  2365. }
  2366.  
  2367. //
  2368. // adds the passed pointer to a child window to the linked list
  2369. // of sibling windows which ChildList points to
  2370. //
  2371. void
  2372. TWindow::AddChild(TWindow* child)
  2373. {
  2374.   if (child)
  2375.     if (ChildList) {
  2376.       child->SiblingList = ChildList->SiblingList;
  2377.       ChildList->SiblingList = child;
  2378.       ChildList = child;
  2379.     }
  2380.     else {
  2381.       ChildList = child;
  2382.       child->SiblingList = child;
  2383.     }
  2384. }
  2385.  
  2386. //
  2387. // Returns a pointer to the TWindow's previous sibling (the window previous to
  2388. // the TWindow in its parent's child window list)
  2389. //
  2390. // Returns the sibling which points to the TWindow
  2391. //
  2392. // If the TWindow was the first child added to the list, returns a pointer to
  2393. // the last child added
  2394. //
  2395. TWindow*
  2396. TWindow::Previous()
  2397. {
  2398.   if (!SiblingList) {
  2399.     return 0;
  2400.   }
  2401.   else {
  2402.     TWindow*  CurrentIndex = this;
  2403.  
  2404.     while (CurrentIndex->Next() != this)
  2405.       CurrentIndex = CurrentIndex->Next();
  2406.  
  2407.     return CurrentIndex;
  2408.   }
  2409. }
  2410.  
  2411. //
  2412. // Returns a pointer to the first TWindow in the ChildList that meets some
  2413. // specified criteria
  2414. //
  2415. // If no child in the list meets the criteria, 0 is returned
  2416. //
  2417. // The Test parameter which defines the criteria, is a pointer to a
  2418. // function that takes a TWindow pointer & a pointer to void
  2419. //
  2420. // The TWindow* will be used as the pointer to the child window and
  2421. // the void* as a pointer to the Test function's additional parameters
  2422. //
  2423. // The Test function must return a Boolean value indicating whether the
  2424. // child passed meets the criteria
  2425. //
  2426. TWindow*
  2427. TWindow::FirstThat(TCondFunc test, void* paramList) const
  2428. {
  2429.   if (ChildList) {
  2430.     TWindow*  nextChild = ChildList->Next();
  2431.     TWindow*  curChild;
  2432.  
  2433.     do {
  2434.       curChild = nextChild;
  2435.       nextChild = nextChild->Next();
  2436.  
  2437.       //
  2438.       // Test curChild for okay
  2439.       //
  2440.       if (test(curChild, paramList))
  2441.         return curChild;
  2442.     } while (curChild != ChildList && ChildList);
  2443.   }
  2444.   return 0;
  2445. }
  2446.  
  2447. //
  2448. // Iterates over each child window in the TWindow's ChildList,
  2449. // calling the procedure whose pointer is passed as the Action to be
  2450. // performed for each child
  2451. //
  2452. // A pointer to a child is passed as the first parameter to the iteration
  2453. // procedure
  2454. //
  2455. void
  2456. TWindow::ForEach(TActionFunc action, void* paramList)
  2457. {
  2458.   if (ChildList) {
  2459.     TWindow*  curChild;
  2460.     TWindow*  nextChild = ChildList->Next();  // Allows ForEach to delete children
  2461.  
  2462.     do {
  2463.       curChild = nextChild;
  2464.       nextChild = nextChild->Next();
  2465.       action(curChild, paramList);
  2466.     } while (curChild != ChildList && ChildList);
  2467.   }
  2468. }
  2469.  
  2470. //
  2471. // Returns a pointer to the first TWindow in the ChildList that
  2472. // meets some specified criteria
  2473. //
  2474. // If no child in the list meets the criteria, 0 is returned
  2475. //
  2476. // The Test parameter which defines the criteria, is a pointer to a member
  2477. // function (this is how it's different from FirstThat above) that takes a
  2478. // pointer to a TWindow & a pointer to void
  2479. //
  2480. // The TWindow pointer will be used as the pointer to the child window and the
  2481. // void pointer as a pointer to the Test function's additional parameters
  2482. //
  2483. // The Test function must return a Boolean value indicating whether the child
  2484. // passed meets the criteria
  2485. //
  2486. TWindow*
  2487. TWindow::FirstThat(TCondMemFunc test, void* paramList)
  2488. {
  2489.   if (ChildList) {
  2490.     TWindow*  nextChild = ChildList->Next();
  2491.     TWindow*  curChild;
  2492.  
  2493.     do {
  2494.       curChild = nextChild;
  2495.       nextChild = nextChild->Next();
  2496.  
  2497.       if ((this->*test)(curChild, paramList))
  2498.         return curChild;
  2499.     } while (curChild != ChildList && ChildList);
  2500.   }
  2501.   return 0;
  2502. }
  2503.  
  2504. //
  2505. // Iterates over each child window in the TWindow's ChildList,
  2506. // calling the member function (unlike ForEach above which takes pointer
  2507. // to non-member function) whose pointer is passed as the Action to
  2508. // be performed for each child
  2509. //
  2510. // A pointer to a child is passed as the first parameter to the iteration
  2511. // procedure
  2512. //
  2513. void
  2514. TWindow::ForEach(TActionMemFunc action, void* paramList)
  2515. {
  2516.   if (ChildList) {
  2517.     TWindow*  nextChild = ChildList->Next();
  2518.     TWindow*  curChild;
  2519.  
  2520.     do {
  2521.       curChild = nextChild;
  2522.       nextChild = nextChild->Next();
  2523.       (this->*action)(curChild, paramList);
  2524.     } while (curChild != ChildList && ChildList);
  2525.   }
  2526. }
  2527.  
  2528. //
  2529. // Returns the position at which the passed child window appears
  2530. // in the TWindow's ChildList
  2531. //
  2532. // If the child does not appear in the list, -1 is returned
  2533. //
  2534. // Zero'th position is ChildList->Next
  2535. //
  2536. static int position;
  2537. static bool isItThisChild1(TWindow* win, void* child)
  2538. {
  2539.   ++position;
  2540.   return win == (TWindow*)child;
  2541. }
  2542.  
  2543. //
  2544. //
  2545. //
  2546. #pragma warn -ncf
  2547. int
  2548. TWindow::IndexOf(TWindow* child) const
  2549. {
  2550.   position = -1;
  2551.   return FirstThat(isItThisChild1, child) ? position : -1;
  2552. }
  2553. #pragma warn .ncf
  2554.  
  2555. //
  2556. // Returns the child at the passed position in the TWindow's
  2557. // ChildList
  2558. //
  2559. // The ChildList is circularly-referent so that passing a position
  2560. // larger than the number of children will cause the traversal of the
  2561. // list to wrap
  2562. //
  2563. // Zero'th position is ChildList->Next
  2564. //
  2565. TWindow*
  2566. TWindow::At(int position)
  2567. {
  2568.   if (position == -1)
  2569.     return 0;
  2570.  
  2571.   else {
  2572.     TWindow*  currentChild = ChildList;
  2573.  
  2574.     if (currentChild) {
  2575.       currentChild = ChildList->Next();
  2576.  
  2577.       while (position > 0) {
  2578.         currentChild = currentChild->Next();
  2579.         position--;
  2580.       }
  2581.     }
  2582.     return currentChild;
  2583.   }
  2584. }
  2585.  
  2586. //
  2587. // Returns a pointer to the window in the ChildList with the passed Id
  2588. //
  2589. // If no child in the list has the passed Id, 0 is returned
  2590. //
  2591. static bool isItThisChild2(TWindow* win, void* id) {
  2592.   return win->GetId() == *(int*)id;
  2593. }
  2594.  
  2595. //
  2596. //
  2597. //
  2598. TWindow*
  2599. TWindow::ChildWithId(int id) const
  2600. {
  2601.   return ((TWindow*)this)->FirstThat(isItThisChild2, &id);
  2602. }
  2603.  
  2604. //
  2605. // Send a message directly to this window using system API. Handles exception
  2606. // resumption for systems that need it.
  2607. //
  2608. TResult
  2609. TWindow::SendMessage(uint msg, TParam1 param1, TParam2 param2)
  2610. {
  2611.   PRECONDITION(GetHandle());
  2612.  
  2613.   TResult result = ::SendMessage(GetHandle(), msg, param1, param2);
  2614.   GetApplication()->ResumeThrow();
  2615.   return result;
  2616. }
  2617.  
  2618. //
  2619. // Forward the current event to a given window. Can either send or post, based
  2620. // on the send argument.
  2621. //
  2622. TResult
  2623. TWindow::ForwardMessage(HWND handle, bool send)
  2624. {
  2625.   if (!handle)
  2626.     return 0;
  2627.  
  2628.   TCurrentEvent& currentEvent = GetCurrentEvent();
  2629.   if (send) {
  2630.     TResult result = ::SendMessage(handle, currentEvent.Message,
  2631.                                    currentEvent.Param1,
  2632.                                    currentEvent.Param2);
  2633.     GetApplication()->ResumeThrow();
  2634.     return result;
  2635.   }
  2636.   else
  2637.     return ::PostMessage(handle, currentEvent.Message,
  2638.                          currentEvent.Param1,
  2639.                          currentEvent.Param2);
  2640. }
  2641.  
  2642. //
  2643. // Forward a message to an Owl window. If send, then bypass windows directly
  2644. // and call the owl window's window proc.
  2645. //
  2646. TResult
  2647. TWindow::ForwardMessage(bool send)
  2648. {
  2649.   TCurrentEvent& currentEvent = GetCurrentEvent();
  2650.   if (send)
  2651.     return HandleMessage(currentEvent.Message, currentEvent.Param1,
  2652.                          currentEvent.Param2);
  2653.   return ForwardMessage(GetHandle(), send);
  2654. }
  2655.  
  2656. //
  2657. // Broadcast a given message to all the children of this window, including
  2658. // non-object windows
  2659. //
  2660. void
  2661. TWindow::ChildBroadcastMessage(uint msg, TParam1 param1, TParam2 param2)
  2662. {
  2663.   for (HWND hWndChild = GetWindow(GW_CHILD); hWndChild; ) {
  2664.     HWND hWndNext = ::GetWindow(hWndChild, GW_HWNDNEXT);
  2665.     ::SendMessage(hWndChild, msg, param1, param2);
  2666.     GetApplication()->ResumeThrow();
  2667.     hWndChild = hWndNext;
  2668.   }
  2669. }
  2670.  
  2671. //
  2672. // Destroys the associated MS-Windows interface element and deletes the C++
  2673. // object unconditionally (without calling CanClose())
  2674. //
  2675. // This function is static to avoid side effects of deleting 'this'.
  2676. //
  2677. void
  2678. TWindow::ShutDownWindow(TWindow* win, int retVal)
  2679. {
  2680.   win->Destroy(retVal);
  2681.   delete win;
  2682. }
  2683.  
  2684. //
  2685. // Sets the Title and caption of this TWindow
  2686. //
  2687. void
  2688. TWindow::SetCaption(const char far* title)
  2689. {
  2690.   if (Title != title) {
  2691.     if (HiUint16(uint32(Title)))
  2692.       delete[] Title;
  2693.  
  2694.     Title = strnewdup(title);
  2695.   }
  2696.  
  2697.   if (GetHandle())
  2698.     ::SetWindowText(GetHandle(), Title);
  2699. }
  2700.  
  2701. //
  2702. // Gets the Title member var from the current window caption or text
  2703. //
  2704. void
  2705. TWindow::GetWindowTextTitle()
  2706. {
  2707.   if (LoUint16(uint32(Title)) == 0xFFFF)  // ignore "don't-change" titles
  2708.     return;
  2709.  
  2710.   if (HiUint16(uint32(Title)))
  2711.     delete[] Title;
  2712.  
  2713.   int titleLength = GetWindowTextLength();
  2714.   if (titleLength < 0) {
  2715.     Title = strnewdup((const char far*)"");
  2716.   }
  2717.   else {
  2718.     Title = new far char[titleLength + 1];
  2719.     Title[0] = 0;
  2720.     Title[titleLength] = 0;
  2721.     GetWindowText(Title, titleLength + 1);
  2722.   }
  2723. }
  2724.  
  2725. //
  2726. // Copy over the styles, the coordinates & the id from the existing HWnd into
  2727. // the Owl TWindow members.
  2728. //   NOTE: the title is not copied here, but in GetWindowTextTitle()
  2729. //
  2730. void
  2731. TWindow::GetHWndState(bool forceStyleSync)
  2732. {
  2733.   // Retrieve Attr.Style and Attr.ExStyle
  2734.   //
  2735.   // NOTE: some windows controls (e.g. EDIT) change the style bits
  2736.   // (e.g. WS_BORDER) from their original values.  if we always reset
  2737.   // Attr.Style and Attr.ExStyle by extracting their values from
  2738.   // Windows, we will lose some of the style bits we supplied
  2739.   // in the CreateWindowEx call.  in the case of the ResourceId
  2740.   // constructors, of course, we must retrieve these values.
  2741.   //
  2742.   if (IsFlagSet(wfFromResource) || forceStyleSync) {
  2743.     Attr.Style = GetWindowLong(GWL_STYLE);
  2744.     Attr.ExStyle = GetWindowLong(GWL_EXSTYLE);
  2745.   }
  2746.  
  2747.   // Retrieve Attr.X, Attr.Y, Attr.W and Attr.H
  2748.   //
  2749.   TRect  wndRect;
  2750.  
  2751.   GetWindowRect(wndRect);
  2752.   Attr.H = wndRect.Height();
  2753.   Attr.W = wndRect.Width();
  2754.  
  2755.   HWND  hParent = GetParentH();
  2756.   if ((Attr.Style & WS_CHILD) && hParent)
  2757.     ::ScreenToClient(hParent, &wndRect.TopLeft());
  2758.  
  2759.   Attr.X = wndRect.left;
  2760.   Attr.Y = wndRect.top;
  2761.  
  2762. #if defined(BI_PLAT_WIN16)
  2763.   Attr.Id = GetWindowWord(GWW_ID);
  2764. #else
  2765.   Attr.Id = GetWindowLong(GWL_ID);
  2766. #endif
  2767. }
  2768.  
  2769. //
  2770. //
  2771. //
  2772. uint
  2773. TWindow::GetDlgItemInt(int childId, bool* translated, bool isSigned) const
  2774. {
  2775.   PRECONDITION(GetHandle());
  2776.  
  2777. #if (sizeof(bool) == sizeof(int))
  2778.   uint retVal = ::GetDlgItemInt(GetHandle(), childId, (int*)translated, isSigned);
  2779. #else
  2780.   int tempTranslated;
  2781.   uint retVal = ::GetDlgItemInt(GetHandle(), childId, &tempTranslated, isSigned);
  2782.   if (translated)
  2783.     *translated = tempTranslated;
  2784. #endif
  2785.   return retVal;
  2786. }
  2787.  
  2788. //
  2789. // Gets/Sets the style bits of the underlying window or the 'Style'
  2790. // member of the attribute structure associated with this TWindow object.
  2791. //
  2792. uint32
  2793. TWindow::GetStyle() const
  2794. {
  2795.   return GetHandle() ? GetWindowLong(GWL_STYLE) : Attr.Style;
  2796. }
  2797.  
  2798. //
  2799. // Gets/Sets the style bits of the underlying window or the 'Style'
  2800. // member of the attribute structure associated with this TWindow object.
  2801. //
  2802. uint32
  2803. TWindow::SetStyle(uint32 style)
  2804. {
  2805.   if (!GetHandle()) {
  2806.     uint32 oldstyle = Attr.Style;
  2807.     Attr.Style = style;
  2808.     return oldstyle;
  2809.   }
  2810.   return SetWindowLong(GWL_STYLE, style);
  2811. }
  2812.  
  2813. //
  2814. // Gets the extra style bits of the window.
  2815. //
  2816. uint32
  2817. TWindow::GetExStyle() const
  2818. {
  2819.   return GetHandle() ? GetWindowLong(GWL_EXSTYLE) : Attr.ExStyle;
  2820. }
  2821.  
  2822. //
  2823. // Sets the extra style bits of the window.
  2824. //
  2825. uint32
  2826. TWindow::SetExStyle(uint32 style)
  2827. {
  2828.   if (!GetHandle()) {
  2829.     uint32 oldstyle = Attr.ExStyle;
  2830.     Attr.ExStyle = style;
  2831.     return oldstyle;
  2832.   }
  2833.   return SetWindowLong(GWL_EXSTYLE, style);
  2834. }
  2835.  
  2836. //
  2837. // Modify the style bits of the window.
  2838. //
  2839. bool
  2840. TWindow::ModifyStyle(uint32 offBits, uint32 onBits, uint swpFlags)
  2841. {
  2842.   uint32 style = GetStyle();
  2843.   uint32 newStyle = (style & ~offBits) | onBits;
  2844.   if (style == newStyle)
  2845.     return false;
  2846.  
  2847.   SetStyle(newStyle);
  2848.  
  2849.   if (swpFlags && GetHandle())
  2850.     SetWindowPos(0, 0, 0, 0, 0,
  2851.                  SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|swpFlags);
  2852.   return true;
  2853. }
  2854.  
  2855. //
  2856. // Modify the style bits of the window.
  2857. //
  2858. bool
  2859. TWindow::ModifyExStyle(uint32 offBits, uint32 onBits, uint swpFlags)
  2860. {
  2861.   uint32 style = GetExStyle();
  2862.   uint32 newStyle = (style & ~offBits) | onBits;
  2863.   if (style == newStyle)
  2864.     return false;
  2865.  
  2866.   SetExStyle(newStyle);
  2867.   if (swpFlags)
  2868.     SetWindowPos(0, 0, 0, 0, 0,
  2869.                  SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|swpFlags);
  2870.   return true;
  2871. }
  2872.  
  2873. //
  2874. // Get the window rectangle whether it has been created or not
  2875. //
  2876. void
  2877. TWindow::GetWindowRect(TRect& rect) const {
  2878.   if (GetHandle()) {
  2879.     ::GetWindowRect(GetHandle(), &rect);
  2880.   }
  2881.   else {
  2882.     rect.SetWH(Attr.X, Attr.Y, Attr.W, Attr.H);
  2883.   }
  2884. }
  2885.  
  2886. //
  2887. // Get the window's client rectangle whether it has been created or not
  2888. //
  2889. void
  2890. TWindow::GetClientRect(TRect& rect) const {
  2891.   if (GetHandle()) {
  2892.     ::GetClientRect(GetHandle(), &rect);
  2893.   }
  2894.   else {
  2895.     rect.Set(0, 0, Attr.W, Attr.H);
  2896.   }
  2897. }
  2898.  
  2899. //
  2900. // Set the new window position.
  2901. //
  2902. bool
  2903. TWindow::SetWindowPos(HWND hWndInsertAfter,
  2904.                       int x, int y, int w, int h,
  2905.                       uint flags)
  2906. {
  2907.   if (GetHandle())
  2908.     return ::SetWindowPos(GetHandle(), hWndInsertAfter, x, y, w, h, flags);
  2909.  
  2910.   if (!(flags & SWP_NOMOVE)) {
  2911.     Attr.X = x;
  2912.     Attr.Y = y;
  2913.   }
  2914.   if (!(flags & SWP_NOSIZE)) {
  2915.     Attr.W = w;
  2916.     Attr.H = h;
  2917.   }
  2918.  
  2919.  
  2920.   if (flags & SWP_SHOWWINDOW)
  2921.     Attr.Style |= WS_VISIBLE;
  2922.   else if (flags & SWP_HIDEWINDOW)
  2923.     Attr.Style &= ~WS_VISIBLE;
  2924.  
  2925.   return true;
  2926. }
  2927.  
  2928. //
  2929. // Displays this TWindow in a given state. Can be called either before or after
  2930. // the Window is created. If before, the show state is placed into Attr for use
  2931. // at creation
  2932. //
  2933. bool
  2934. TWindow::ShowWindow(int cmdShow)
  2935. {
  2936.   // If the window is being minimzed send a WM_SYSCOMMAND; this way the
  2937.   // frame window focus saving works properly
  2938.   //
  2939.   if (GetHandle()) {
  2940.     if (cmdShow == SW_MINIMIZE)
  2941.       return HandleMessage(WM_SYSCOMMAND, SC_MINIMIZE);
  2942.  
  2943.     else
  2944.       return ::ShowWindow(GetHandle(), cmdShow);
  2945.   }
  2946.  
  2947.   switch (cmdShow) {
  2948.     case SW_HIDE:
  2949.       Attr.Style &= ~WS_VISIBLE;
  2950.       break;
  2951.     case SW_SHOWNORMAL:
  2952.     case SW_RESTORE:
  2953.       Attr.Style |= WS_VISIBLE;
  2954.       Attr.Style &= ~(WS_MINIMIZE | WS_MAXIMIZE);
  2955.       break;
  2956.     case SW_SHOWMINIMIZED:
  2957.     case SW_MINIMIZE:
  2958.     case SW_SHOWMINNOACTIVE:
  2959.       Attr.Style |= WS_VISIBLE;
  2960.       Attr.Style |= WS_MINIMIZE;
  2961.       break;
  2962.     case SW_SHOWMAXIMIZED:
  2963.       Attr.Style |= WS_VISIBLE;
  2964.       Attr.Style |= WS_MAXIMIZE;
  2965.       break;
  2966.     case SW_SHOWNOACTIVATE:
  2967.     case SW_SHOW:
  2968.     case SW_SHOWNA:
  2969.       Attr.Style |= WS_VISIBLE;
  2970.       break;
  2971.   }
  2972.   return true;
  2973. }
  2974.  
  2975. //
  2976. // Set the cursor for this window given a TModule and a resId
  2977. // Updates the current cursor if it is over this window.
  2978. //
  2979. bool
  2980. TWindow::SetCursor(TModule* module, TResId resId)
  2981. {
  2982.   if (module == CursorModule && resId == CursorResId)
  2983.     return false;
  2984.  
  2985.   HCURSOR hOldCursor = (HCursor && CursorModule) ? HCursor : 0;
  2986.  
  2987.   CursorModule = module;
  2988.   CursorResId = resId;
  2989.   if (CursorResId)
  2990.     if (CursorModule)
  2991.       HCursor = CursorModule->LoadCursor(CursorResId);
  2992.     else
  2993.       HCursor = ::LoadCursor(0, CursorResId);
  2994.   else
  2995.     HCursor = 0;
  2996.  
  2997.   // If the cursor is in our client window then set it now
  2998.   //
  2999.   if (GetHandle()) {
  3000.     TPoint p;
  3001.     GetCursorPos(p);
  3002.     ScreenToClient(p);
  3003.     if (GetClientRect().Contains(p))
  3004.       ::SetCursor(HCursor);
  3005.   }
  3006.  
  3007.   // Destroy old cursor if there was one & it was not loaded from USER
  3008.   //
  3009.   if (hOldCursor)
  3010.     ::DestroyCursor(hOldCursor);
  3011.   return true;
  3012. }
  3013.  
  3014. //
  3015. // Handle WM_INITMENUPOPUP while embeded to generate command enable messages
  3016. // for our server menu items. Very similar to TFrameWindow::EvInitMenuPopup;
  3017. // could rearrange code to share better.
  3018. //
  3019. void
  3020. TWindow::EvInitMenuPopup(HMENU hPopupMenu, uint /*index*/, bool sysMenu)
  3021. {
  3022.   if (IsFlagSet(wfAlias))
  3023.     DefaultProcessing();
  3024.  
  3025.   else if (!sysMenu && hPopupMenu) {
  3026.     const int count = ::GetMenuItemCount(hPopupMenu);
  3027.  
  3028.     for (int pos = 0; pos < count; pos++) {
  3029.       uint  id;
  3030.  
  3031.       if (hPopupMenu == GetMenu()) // top level menu
  3032.         id = ::GetMenuItemID(hPopupMenu, pos);
  3033.  
  3034.       else {
  3035.         // For second level and below menus, return the implied id for popup
  3036.         // sub-menus. The implied id for a sub-menu is the id of the first item
  3037.         // in the popup sub-menu less 1. If there are more than one level of
  3038.         // popup menus, it will recursively look into those sub-menus as well.
  3039.         //
  3040.         TMenu popupMenu(hPopupMenu);
  3041.         id = popupMenu.GetMenuItemID(pos);
  3042.       }
  3043.  
  3044.       // Ignore separators
  3045.       //
  3046.       if (id == 0 || uint16(id) == uint16(-1))
  3047.         continue;
  3048.  
  3049.       // Skip the rest if it is the mdi child list, or system commands
  3050.       //
  3051.       if (id == IDW_FIRSTMDICHILD || id > 0xF000)
  3052.         break;
  3053.  
  3054.       EvCommandEnable(TMenuItemEnabler(hPopupMenu, id, GetHandle(), pos));
  3055.     }
  3056.   }
  3057. }
  3058.  
  3059. //
  3060. // Associate a popup menu with the window so that it can automatically
  3061. // handle a WM_CONTEXTMENU message.
  3062. //
  3063. void
  3064. TWindow::AssignContextMenu(TPopupMenu* popupMenu)
  3065. {
  3066.   delete ContextPopupMenu;
  3067.   ContextPopupMenu = popupMenu;
  3068. }
  3069.  
  3070. //
  3071. // Respond to a right button click in window.
  3072. //
  3073. void
  3074. TWindow::EvContextMenu(HWND /*child*/, int x, int y)
  3075. {
  3076.   if (GetContextMenu()) {
  3077.     GetContextMenu()->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
  3078.                                      x, y, 0, *this, 0);
  3079.   }
  3080.   else {
  3081.     // Allow 'wfPredefined' and 'wfAlias' classes to handle the ContextMenu
  3082.     // event.
  3083.     //
  3084.     DefaultProcessing();
  3085.   }
  3086. }
  3087.  
  3088. //
  3089. //
  3090. //
  3091. void
  3092. TWindow::EvEnterIdle(uint source, HWND hWndDlg)
  3093. {
  3094.   // If we're the main window, let it rip from the receiver
  3095.   //
  3096.   if (source == MSGF_DIALOGBOX) {
  3097.     if (IsFlagSet(wfMainWindow))
  3098.       IdleAction(0);
  3099.     else {
  3100.       TWindow* win = GetWindowPtr(hWndDlg);
  3101.       if (win)
  3102.         win->IdleAction(0);
  3103.     }
  3104.   }
  3105.  
  3106.   // Let original proc. have a crack at msg.
  3107.   //
  3108.   DefaultProcessing();
  3109. }
  3110.  
  3111. //
  3112. // Wrapper for Windows API.
  3113. //
  3114. int
  3115. TWindow::GetScrollPos(int bar) const
  3116. {
  3117.   PRECONDITION(GetHandle());
  3118. #if defined(BI_PLAT_WIN16)
  3119.   return ::GetScrollPos(GetHandle(), bar);
  3120. #else
  3121.   SCROLLINFO info;
  3122.   ZeroMemory(&info, sizeof info);
  3123.   info.cbSize = sizeof info;
  3124. //  info.fMask = SIF_DISABLENOSCROLL | SIF_POS;
  3125.   info.fMask = SIF_POS;
  3126.   GetScrollInfo(bar, &info);
  3127.   return info.nPos;
  3128. #endif
  3129. }
  3130.  
  3131. //
  3132. // Wrapper for Windows API.
  3133. //
  3134. int
  3135. TWindow::SetScrollPos(int bar, int pos, bool redraw)
  3136. {
  3137.   PRECONDITION(GetHandle());
  3138. #if defined(BI_PLAT_WIN16)
  3139.   return ::SetScrollPos(GetHandle(), bar, pos, redraw);
  3140. #else
  3141.   int oldPos = GetScrollPos(bar);
  3142.  
  3143.   SCROLLINFO info;
  3144.   ZeroMemory(&info, sizeof info);
  3145.   info.cbSize = sizeof info;
  3146.   info.fMask = SIF_POS;
  3147.   info.nPos = pos;
  3148.   SetScrollInfo(bar, &info, redraw);
  3149.   return oldPos;
  3150. #endif
  3151. }
  3152.  
  3153. //
  3154. // Wrapper for Windows API.
  3155. //
  3156. void
  3157. TWindow::GetScrollRange(int bar, int& minPos, int& maxPos) const
  3158. {
  3159.   PRECONDITION(GetHandle());
  3160. #if defined(BI_PLAT_WIN16)
  3161.   ::GetScrollRange(GetHandle(), bar, &minPos, &maxPos);
  3162. #else
  3163.   SCROLLINFO info;
  3164.   ZeroMemory(&info, sizeof info);
  3165.   info.cbSize = sizeof info;
  3166.   info.fMask = SIF_RANGE;
  3167.   GetScrollInfo(bar, &info);
  3168.   minPos = info.nMin;
  3169.   maxPos = info.nMax;
  3170. #endif
  3171. }
  3172.  
  3173. //
  3174. // Wrapper for Windows API.
  3175. //
  3176. void
  3177. TWindow::SetScrollRange(int bar, int minPos, int maxPos, bool redraw)
  3178. {
  3179.   PRECONDITION(GetHandle());
  3180. #if defined(BI_PLAT_WIN16)
  3181.   ::SetScrollRange(GetHandle(), bar, minPos, maxPos, redraw);
  3182. #else
  3183.   SCROLLINFO info;
  3184.   ZeroMemory(&info, sizeof info);
  3185.   info.cbSize = sizeof info;
  3186.   info.fMask = SIF_RANGE;
  3187.   info.nMin = minPos;
  3188.   info.nMax = maxPos;
  3189.   SetScrollInfo(bar, &info, redraw);
  3190. #endif
  3191. }
  3192.  
  3193. #pragma warn -par
  3194. //
  3195. //
  3196. //
  3197. void
  3198. TWindow::SetScrollPage(int bar, int page, bool redraw)
  3199. {
  3200.   PRECONDITION(GetHandle());
  3201. #if defined(BI_PLAT_WIN16)
  3202. #else
  3203.   SCROLLINFO info;
  3204.   ZeroMemory(&info, sizeof info);
  3205.   info.cbSize = sizeof info;
  3206.   info.fMask = SIF_PAGE;
  3207.   info.nPage = page;
  3208.   SetScrollInfo(bar, &info, redraw);
  3209. #endif
  3210. }
  3211. #pragma warn .par
  3212.  
  3213. #pragma warn -par
  3214. //
  3215. //
  3216. //
  3217. int
  3218. TWindow::GetScrollPage(int bar) const
  3219. {
  3220.   PRECONDITION(GetHandle());
  3221. #if defined(BI_PLAT_WIN16)
  3222.   return 0;
  3223. #else
  3224.   SCROLLINFO info;
  3225.   ZeroMemory(&info, sizeof info);
  3226.   info.cbSize = sizeof info;
  3227.   info.fMask = SIF_PAGE;
  3228.   GetScrollInfo(bar, &info);
  3229.   return info.nPage;
  3230. #endif
  3231. }
  3232. #pragma warn .par
  3233.  
  3234. #if defined(BI_PLAT_WIN32)
  3235. //
  3236. //
  3237. //
  3238. void
  3239. TWindow::SetScrollInfo(int bar, SCROLLINFO* scrollInfo, bool redraw)
  3240. {
  3241.   PRECONDITION(GetHandle());
  3242.   ::SetScrollInfo(GetHandle(), bar, scrollInfo, redraw);
  3243. }
  3244.  
  3245. //
  3246. //
  3247. //
  3248. void
  3249. TWindow::GetScrollInfo(int bar, SCROLLINFO* scrollInfo) const
  3250. {
  3251.   PRECONDITION(GetHandle());
  3252.   ::GetScrollInfo(GetHandle(), bar, scrollInfo);
  3253. }
  3254. #endif
  3255.  
  3256. //
  3257. // Not inline to avoid requiring gdiobjec.h by window.h just to get TRegion's
  3258. // conversion operator
  3259. //
  3260. bool
  3261. TWindow::GetUpdateRgn(TRegion& region, bool erase) const
  3262. {
  3263.   PRECONDITION(GetHandle());
  3264.  
  3265.   return ::GetUpdateRgn(GetHandle(), region, erase);
  3266. }
  3267.  
  3268. //
  3269. //
  3270. //
  3271. #if defined(__TRACE) || defined(__WARN)
  3272.  
  3273. #if defined(BI_NAMESPACE)
  3274. namespace OWL {
  3275. #endif 
  3276.  
  3277.   ostream& operator <<(ostream& os, const TWindow& w)
  3278.   {
  3279.     os << '(';
  3280. #if !defined(BI_NO_RTTI)
  3281.       os << typeid(w).name() << ',';
  3282. #else
  3283.       os << _TYPENAME(&w) << ',';
  3284. #endif
  3285.     os << "0x" << hex << uint(w.GetHandle()) << ',';
  3286.     if (w.Title)
  3287.       os << '\'' << TResId(w.Title) << '\'' << ',';
  3288.     if (w.Parent)
  3289.       os << "id=" << w.GetId();
  3290.     os << ')';
  3291.     return os;
  3292.   }
  3293.   
  3294. #if defined(BI_NAMESPACE)
  3295. } // namespace OWL
  3296. #endif 
  3297.  
  3298. #endif // __TRACE || __WARN
  3299.  
  3300.  
  3301. //
  3302. // Returns a string which kind-of identifies the window (used during autopsy
  3303. // and vivisection of dead/dying window)
  3304. //
  3305. static const char*
  3306. winInfo(TWindow* win)
  3307. {
  3308.   const char noTitle[] = "Untitled";
  3309.   static char winStr[80];
  3310.   if (win) {
  3311.     sprintf(winStr, "%s, %u, %s",
  3312.                     HiUint16(uint32(win->Title)) ? win->Title : noTitle,
  3313.                     win->Attr.Id, _TYPENAME(win));
  3314.     return winStr;
  3315.   }
  3316.   return "";
  3317. }
  3318.  
  3319. #if defined(OWL2_COMPAT)
  3320. //
  3321. // For backward compatibility
  3322. //
  3323. string
  3324. TXWindow::Msg(TWindow* win, uint resId)
  3325. {
  3326.   return MakeMessage(resId, winInfo(win));
  3327. }
  3328. #endif
  3329.  
  3330. //
  3331. // InvalidWindow exception constructor
  3332. //
  3333. TXWindow::TXWindow(TWindow* win, uint resId)
  3334. :
  3335.   TXOwl(MakeMessage(resId, winInfo(win)), resId),
  3336.   Window(win)
  3337. {
  3338. }
  3339.  
  3340. //
  3341. // Copy the exception object.
  3342. //
  3343. TXWindow::TXWindow(const TXWindow& src)
  3344. :
  3345.   TXOwl(src),
  3346.   Window(src.Window)
  3347. {
  3348. }
  3349.  
  3350. //
  3351. // Unhandled exception.
  3352. //
  3353. int
  3354. TXWindow::Unhandled(TModule* app, uint promptResId)
  3355. {
  3356.   Window = 0;
  3357.   return TXOwl::Unhandled(app, promptResId);
  3358. }
  3359.  
  3360. //
  3361. // Clone the exception object for safe-throwing in Win16.
  3362. //
  3363. #if defined(BI_NO_COVAR_RET)
  3364. TXBase*
  3365. #else
  3366. TXWindow*
  3367. #endif
  3368. TXWindow::Clone()
  3369. {
  3370.   return new TXWindow(*this);
  3371. }
  3372.  
  3373. //
  3374. // Throw the exception.
  3375. //
  3376. void
  3377. TXWindow::Throw()
  3378. {
  3379.   THROW( *this );
  3380. }
  3381.  
  3382. //
  3383. // Creates the TXWindow exception and throws it.
  3384. //
  3385. void
  3386. TXWindow::Raise(TWindow* win, uint resourceId)
  3387. {
  3388.   TXWindow(win, resourceId).Throw();
  3389. }
  3390.